Handling errors
We've already briefly touched handling errors in dispatchers in the Getting Started section, but let's dive a bit deeper.
Registering a handler
An error handler for a Dispatcher is simply a function that is called whenever an error is thrown inside one of the handlers.
For convenience, that function has access to the error itself, the parsed update and the state (if applicable):
dp.onNewMessage(
filters.command('do_stuff'),
async (msg) => {
throw new Error('Some error')
}
)
dp.onError(async (error, update, state) => {
if (update.name === 'new_message') {
await update.data.replyText(`Error: ${error.message}`)
return true
}
return false
})
dp.onNewMessage(
filters.command('do_stuff'),
async (msg) => {
throw new Error('Some error')
}
)
dp.onError(async (error, update, state) => {
if (update.name === 'new_message') {
await update.data.replyText(`Error: ${error.message}`)
return true
}
return false
})
Error handler function is expected to return boolean
indicating whether the update was handled. If it was not, it will be propagated to Client.
update
is an object that contains 2 fields: name
and data
.
name
is simply update name (new_message
, edit_message
, etc.; see Handlers), and data
is the respective object.
What errors are not handled
Errors inside Raw update handlers are not handled by the error handler. Any other errors within the same dispatcher (both handlers and filters) are handled by it.
Propagation
To Client
If the error handler is not registered, throws an error or returns false
, the error is propagated to Client's error handler. Obviously, in Client's error handler you won't have access to the update that caused this error:
dp.onNewMessage(
filters.command('do_stuff'),
async (msg) => {
throw new Error('Some error')
}
)
tg.onError((err) => {
// will be called since there's no `dp.onError`
console.log(err)
})
dp.onNewMessage(
filters.command('do_stuff'),
async (msg) => {
throw new Error('Some error')
}
)
tg.onError((err) => {
// will be called since there's no `dp.onError`
console.log(err)
})
Within the Dispatcher
When an error is thrown by one of the handlers, propagation within this dispatcher stops (the same way as if it returned StopPropagation
):
dp.onNewMessage(
filters.command('do_stuff'),
async (msg) => {
throw new Error('Some error')
}
)
dp.onNewMessage(
async (msg) => {
// will not reach
}
)
dp.onNewMessage(
filters.command('do_stuff'),
async (msg) => {
throw new Error('Some error')
}
)
dp.onNewMessage(
async (msg) => {
// will not reach
}
)
To parent/children
Errors are not propagated to parent dispatcher or to any of the children dispatchers:
const dp = new Dispatcher(tg)
const dp1 = new Dispatcher()
const dp2 = new Dispatcher()
dp.addChild(dp1)
dp1.addChild(dp2)
// dp --child--> dp1 --child--> dp2
dp.onError(() => console.log('DP caught error'))
dp1.onError(() => console.log('DP1 caught error'))
dp2.onError(() => console.log('DP2 caught error'))
dp1.onNewMessage(() => { throw new Error() })
// Only "DP1 caught error" will ever be printed
const dp = new Dispatcher(tg)
const dp1 = new Dispatcher()
const dp2 = new Dispatcher()
dp.addChild(dp1)
dp1.addChild(dp2)
// dp --child--> dp1 --child--> dp2
dp.onError(() => console.log('DP caught error'))
dp1.onError(() => console.log('DP1 caught error'))
dp2.onError(() => console.log('DP2 caught error'))
dp1.onNewMessage(() => { throw new Error() })
// Only "DP1 caught error" will ever be printed
However, if you need that behaviour, you can use propagateErrorToParent
:
const dp = new Dispatcher(tg)
const dp1 = new Dispatcher()
const dp2 = new Dispatcher()
dp.addChild(dp1)
dp1.addChild(dp2)
// dp --child--> dp1 --child--> dp2
dp.onError(() => console.log('DP caught error'))
dp1.onError(() => {
console.log('DP1 caught error')
return dp1.propagateErrorToParent(...arguments)
})
dp2.onError(() => console.log('DP2 caught error'))
dp1.onNewMessage(() => { throw new Error() })
// "DP1 caught error" and "DP caught error" will be printed for each new message
const dp = new Dispatcher(tg)
const dp1 = new Dispatcher()
const dp2 = new Dispatcher()
dp.addChild(dp1)
dp1.addChild(dp2)
// dp --child--> dp1 --child--> dp2
dp.onError(() => console.log('DP caught error'))
dp1.onError(() => {
console.log('DP1 caught error')
return dp1.propagateErrorToParent(...arguments)
})
dp2.onError(() => console.log('DP2 caught error'))
dp1.onNewMessage(() => { throw new Error() })
// "DP1 caught error" and "DP caught error" will be printed for each new message