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```py\n{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:\Users\User\AppData\Local\Programs\Python\Python38\lib\site-packages\discord\commands\core.py", line 127, in wrapped
ret = await coro(arg)
File "C:\Users\User\AppData\Local\Programs\Python\Python38\lib\site-packages\discord\commands\core.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:\Users\User\AppData\Local\Programs\Python\Python38\lib\site-packages\discord\bot.py", line 992, in invoke_application_command
await ctx.command.invoke(ctx)
File "C:\Users\User\AppData\Local\Programs\Python\Python38\lib\site-packages\discord\commands\core.py", line 358, in invoke
await injected(ctx)
File "C:\Users\User\AppData\Local\Programs\Python\Python38\lib\site-packages\discord\commands\core.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```py\n{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?
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.
@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```py\n{''.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__)