Skip to content

Handling errors

There are two ways to write error-free programs; only the third one works

© Alan J. Perlis

Errors are an inevitable part of any software development, especially when working with external APIs, and it is important to know how to handle them.

RPC Errors

Almost any RPC call can result in an RPC error (like FLOOD_WAIT_%d, CHAT_ID_INVALID, etc.).

All these RPC errors are instances of tl.RpcError.

Sadly, JavaScript does not provide a nice syntax to handle different kinds of errors, so you will need to write a bit of boilerplate:

ts
try {
  // your code //
} catch (e) {
  if (tl.RpcError.is(e, 'FLOOD_WAIT_%d')) {
    // handle...
  } else throw e
}
try {
  // your code //
} catch (e) {
  if (tl.RpcError.is(e, 'FLOOD_WAIT_%d')) {
    // handle...
  } else throw e
}

TIP

mtcute automatically handles flood waits smaller than floodWaitThreshold by sleeping for that amount of seconds.

Unknown errors

Sometimes, Telegram with return an error which is not documented (yet). In this case, it will still be an RpcError, but will have .unknown = true

If you are feeling generous and want to help improve the docs for everyone, you can opt into sending unknown errors to danog's error reporting service.

This is fully anonymous (except maybe IP) and is only used to improve the library and developer experience for everyone working with MTProto.

To enable, pass enableErrorReporting: true to the client options:

ts
const tg = new TelegramClient({
  ...
  enableErrorReporting: true
})
const tg = new TelegramClient({
  ...
  enableErrorReporting: true
})

Errors with parameters

Some errors (like FLOOD_WAIT_%d) also contain a parameter. This parameter is available as error's field (in this case in .seconds field) after checking for error type using .is():

ts
try {
  // your code //
} catch (e) {
  if (tl.RpcError.is(e, 'FLOOD_WAIT_%d')) {
    await new Promise((res) => setTimeout(res, e.seconds))
  } else throw e
}
try {
  // your code //
} catch (e) {
  if (tl.RpcError.is(e, 'FLOOD_WAIT_%d')) {
    await new Promise((res) => setTimeout(res, e.seconds))
  } else throw e
}

mtcute errors

mtcute has a group of its own errors that are used to indicate that the provided input is invalid, or that the server returned something weird.

All these errors are subclassed from MtcuteError:

NameDescriptionPackage
MtArgumentErrorSome argument passed to the method appears to be incorrect in some waycore
MtSecurityErrorSomething isn't right with security of the connectioncore
MtUnsupportedErrorServer returned something that mtcute does not support (yet). Should not normally happen, and if it does, feel free to open an issue.core
MtTypeAssertionErrorServer returned some type, but mtcute expected it to be another type. Usually means a bug on mtcute side, so feel free to open an issue.
MtTimeoutErrorTimeout for the request has been reachedcore
MtPeerNotFoundErrorOnly thrown by resolvePeer. Means that mtcute wasn't able to find a peer for a given InputPeerLike.client
MtMessageNotFoundErrormtcute hasn't been able to find a message by the given parametersclient
MtInvalidPeerTypeErrormtcute expected another type of peer (e.g. you provided a user, but a channel was expected).client
MtEmptyErrorYou tried to access some property that is not available on the objectclient

Client errors

Even though these days internet is much more stable than before, stuff like "Error: Connection reset" still happens.

Also, there might be some client-level error that happened internally (e.g. error while processing updates).

You can handle these errors using TelegramClient#onError:

ts
const tg = new TelegramClient(...)

tg.onError((err, conn) => {
  if (conn) {
    // `err` is the error
    // `conn` is the connection where the error happened
    console.log(err, conn)
  }

  // `err` is not a connection-related error
  console.log(err)
})
const tg = new TelegramClient(...)

tg.onError((err, conn) => {
  if (conn) {
    // `err` is the error
    // `conn` is the connection where the error happened
    console.log(err, conn)
  }

  // `err` is not a connection-related error
  console.log(err)
})

TIP

mtcute handles reconnection and stuff automatically, so you don't need to call .connect() again!

This should primarily be used for logging and debugging

Dispatcher errors

Learn more in Dispatcher section.

Unhandled errors that had happened inside dispatcher's handlers can be handled as well:

ts
const dp = new Dispatcher()

dp.onError((error, update, state) => {
  console.log(error)

  // to indicate that the error was handled
  return true
})
const dp = new Dispatcher()

dp.onError((error, update, state) => {
  console.log(error)

  // to indicate that the error was handled
  return true
})

Dispatcher errors are local, meaning that they only trigger error handler within the current dispatcher, and do not propagate to parent/children. They also stop propagation within this dispatcher.

If there is no dispatcher error handler, but an error still occurs, the error is propagated to TelegramClient (conn will be undefined).

mtcute is not affiliated with Telegram.