77from discord .ext .commands .errors import (
88 BotMissingPermissions ,
99 CheckFailure ,
10+ CommandInvokeError ,
1011 CommandNotFound ,
1112 MissingPermissions ,
1213 NoPrivateMessage ,
@@ -24,6 +25,12 @@ class ErrorHandling:
2425 event_error_handlers : List [EventErrorHandler ] = field (default_factory = list )
2526 command_error_handlers : List [CommandErrorHandler ] = field (default_factory = list )
2627
28+ def _get_root_error (self , error : Exception ) -> Exception :
29+ if isinstance (error , CommandInvokeError ):
30+ return error .original
31+ else :
32+ return error
33+
2734 def add_event_error_handler (self , handler : EventErrorHandler ):
2835 self .event_error_handlers .append (handler )
2936
@@ -42,48 +49,68 @@ async def reply(
4249 allowed_mentions = allowed_mentions or AllowedMentions .none (),
4350 )
4451
45- async def on_event_error (self , error : Exception , event_data : EventData ):
46- # TODO Can we handle certain types of event errors? #enhance
47- handled = False
52+ async def on_event_error (self , ex : Exception , event_data : EventData ):
53+ # Extract the root error.
54+ error = self . _get_root_error ( ex )
4855
49- # Re-raise the error so that it can be printed to the console.
50- try :
51- raise error
52- except :
53- self .log .exception (f"Ignoring exception in event `{ event_data .name } `" )
56+ # Attempt to handle the error ourselves.
57+ handled = await self .try_handle_event_error (error , event_data )
5458
5559 # Run the error through our registered event error handlers.
5660 for handler in self .event_error_handlers :
5761 try :
58- await handler (error , event_data , handled )
62+ if result := await handler (error , event_data , handled ):
63+ handled = result
5964 except :
6065 # If something went wrong here, print another exception to the console.
6166 self .log .exception ("Handler for command errors caused another error:" )
6267
63- async def on_command_error (self , error : Exception , ctx : Context ):
64- # Attempt to handle the error.
65- handled = await self .try_handle_command_error (ctx , error )
66-
67- # If it wasn't handled, re-raise so it can be printed to the console, and then
68- # let the user know something went wrong.
68+ # If it wasn't handled, re-raise so it can be printed to the console.
6969 if not handled :
7070 try :
7171 raise error
7272 except :
7373 self .log .exception (
74- f"Ignoring exception in cog `{ ctx . cog } ` from command: { ctx . command } "
74+ f"Ignoring unhandled exception in event `{ event_data . name } ` "
7575 )
76- await self .reply (ctx , f"🔥 Something went wrong trying to do that." )
7776
78- # Run the error through our registered command error handlers.
77+ async def try_handle_event_error (
78+ self , error : Exception , event_data : EventData
79+ ) -> bool :
80+ # TODO Can we handle certain types of event errors? #enhance
81+ return False
82+
83+ async def on_command_error (self , ex : Exception , ctx : Context ):
84+ # Extract the root error.
85+ error = self ._get_root_error (ex )
86+
87+ # Attempt to handle the error ourselves.
88+ handled = await self .try_handle_command_error (error , ctx )
89+
90+ # Pipe the error through our registered command error handlers, regardless of
91+ # whether the error was handled. Handlers can decide on their own whether to do
92+ # anything with errors that have already been handled.
7993 for handler in self .command_error_handlers :
8094 try :
81- await handler (error , ctx , handled )
95+ if result := await handler (error , ctx , handled ):
96+ handled = result
8297 except :
8398 # If something went wrong here, print another exception to the console.
8499 self .log .exception ("Handler for command errors caused another error:" )
85100
86- async def try_handle_command_error (self , ctx : Context , error : Exception ) -> bool :
101+ # If it wasn't handled, re-raise so it can be printed to the console, and then
102+ # let the user know something went wrong.
103+ if not handled :
104+ try :
105+ raise error
106+ except :
107+ cog_name = ctx .cog .__cog_name__ if ctx .cog else None
108+ self .log .exception (
109+ f"Ignoring unhandled exception in cog `{ cog_name } ` from command: `{ ctx .command } `"
110+ )
111+ await self .reply (ctx , f"🔥 Something went wrong trying to do that." )
112+
113+ async def try_handle_command_error (self , error : Exception , ctx : Context ) -> bool :
87114 if isinstance (error , CommandNotFound ):
88115 return True
89116 elif isinstance (error , UserInputError ):
@@ -105,4 +132,5 @@ async def try_handle_command_error(self, ctx: Context, error: Exception) -> bool
105132 elif isinstance (error , ResponsiveException ):
106133 await error .respond (ctx )
107134 return True
135+
108136 return False
0 commit comments