I want to write an error handler for my commands that would send the traceback in my dms using Pycord version 2.0.0. I first tried setting up per-command handlers using @command.error
:
# Libraries import discord from traceback import format_exc # Project files import logic bot = discord.Bot() @bot.slash_command(guild_ids=logic.dev_ids, name="exception-test", description="Raises an exception to test error-handling.") async def exception_test(ctx): raise ZeroDivisionError @exception_test.error async def exception_test_error(ctx, error): await ctx.respond("An exception has occurred! Sending traceback...") me = await bot.fetch_user(logic.MY_ID) or bot.get_user(logic.MY_ID) full_error = format_exc() await me.send(f"**An exception has occurred!** (User {ctx.user} used /" f"{ctx.command.qualified_name} with args {ctx.selected_options})n```pyn{full_error}```") bot.run(logic.ds_token)
This works perfectly fine (Message sent to DMs goes as follows):
An exception has occurred! (User MrQez#0333 used /exception-test with args None)
Traceback (most recent call last): File "C:UsersUserAppDataLocalProgramsPythonPython38libsite-packagesdiscordcommandscore.py", line 127, in wrapped ret = await coro(arg) File "C:UsersUserAppDataLocalProgramsPythonPython38libsite-packagesdiscordcommandscore.py", line 881, in _invoke await self.callback(ctx, **kwargs) File "E:/Data/exception-test.py", line 14, in exception_test raise ZeroDivisionError ZeroDivisionError The above exception was the direct cause of the following exception: Traceback (most recent call last): File "C:UsersUserAppDataLocalProgramsPythonPython38libsite-packagesdiscordbot.py", line 992, in invoke_application_command await ctx.command.invoke(ctx) File "C:UsersUserAppDataLocalProgramsPythonPython38libsite-packagesdiscordcommandscore.py", line 358, in invoke await injected(ctx) File "C:UsersUserAppDataLocalProgramsPythonPython38libsite-packagesdiscordcommandscore.py", line 135, in wrapped raise ApplicationCommandInvokeError(exc) from exc discord.errors.ApplicationCommandInvokeError: Application Command raised an exception: ZeroDivisionError:
However, as the amount of commands in my bot grew, the per-command approach was starting to become inefficient. So, I tried a more global approach:
@bot.event async def on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException): await ctx.respond("An exception has occurred! Sending traceback...") me = await bot.fetch_user(logic.MY_ID) or bot.get_user(logic.MY_ID) full_error = format_exc() await me.send(f"**An exception has occurred!** (User {ctx.user} used /" f"{ctx.command.qualified_name} with args {ctx.selected_options})n```pyn{full_error}```")
This returns a disappointing result:
An exception has occurred! (User MrQez#0333 used /exception-test with args None)
NoneType: None
Why do these error-handlers return a different result? And how can I fix my on_application_command_error
solution so that it returns the traceback?
Advertisement
Answer
Explanation
A simple solution would be to, instead of getting the error from sys.exc_info
(format_exc
does this for you), just use the DiscordException
provided to you.
Code
@bot.event async def on_application_command_error(ctx: discord.ApplicationContext, error: discord.DiscordException): await ctx.respond("An exception has occurred! Sending traceback...") full_error = traceback.format_exception(error) await ctx.channel.send(f"**An exception has occurred!** (User {ctx.user} used /" f"{ctx.command.qualified_name} with args {ctx.selected_options})n```pyn{''.join(full_error)}```")
In Python <3.10, replace
full_error = traceback.format_exception(error)
with
full_error = traceback.format_exception(type(error), error, error.__traceback__)