Skip to main content
By default, errors thrown from handler methods propagate out of the generated router. Decorating one method with [ExceptionHandler] changes this: the generated router invokes it from HandleErrorAsync for every update-handling failure instead of letting errors bubble unhandled. The method receives the exception alongside any DI services it needs, and a throw from the handler itself is swallowed to keep the polling loop alive.

Declaring an exception handler

Place [ExceptionHandler] on exactly one static or instance method anywhere in your project. The method must return Task or ValueTask.

Parameter resolution

Parameters are resolved the same way as handler parameters, with two differences:
  • Exception, HandleErrorSource, ITelegramBotClient, and CancellationToken are injected from the error callback arguments directly.
  • Everything else is resolved from the DI container — including keyed services via [Key("name")] T.
  • Update-bound parameters are not available. There is no current update in the error path. Declaring a parameter that would normally be bound to an update payload (e.g. Message, Update) or a keyed service without a constant key is rejected at compile time with CUR032.

Keyed service injection

Return types

The method must return Task or ValueTask. Any other return type is a compile-time error (CUR034). Both async/await and synchronous (return Task.CompletedTask) styles work.

Fault isolation

A throw inside the [ExceptionHandler] method itself is caught and swallowed by the generated router. This guarantees the polling loop survives even if your error reporting logic has a bug.
Because throws from [ExceptionHandler] are swallowed, make sure your error handler logs or reports synchronously before awaiting anything that could fail. Otherwise you may lose error context silently.

Only one handler allowed

Declaring more than one method with [ExceptionHandler] is a compile-time error (CUR033). There is exactly one HandleErrorAsync override in the generated router.

Full example with structured logging

Diagnostics reference

Severity: ErrorA [ExceptionHandler] method declares a parameter that is update-bound (e.g. Message, Update, CallbackQuery) or keyed with a non-constant key. There is no current update in the error path; the parameter is dropped.
Severity: ErrorMore than one method carries [ExceptionHandler]. Only one HandleErrorAsync override is generated; declare exactly one exception handler.
Severity: ErrorThe [ExceptionHandler] method does not return Task or ValueTask. The method is rejected and no error override is generated.