Skip to content

Instantly share code, notes, and snippets.

@EvieePy
Last active May 27, 2024 17:01
Show Gist options
  • Save EvieePy/7822af90858ef65012ea500bcecf1612 to your computer and use it in GitHub Desktop.
Save EvieePy/7822af90858ef65012ea500bcecf1612 to your computer and use it in GitHub Desktop.
Simple Error Handling for ext.commands - discord.py
"""
If you are not using this inside a cog, add the event decorator e.g:
@bot.event
async def on_command_error(ctx, error)
For examples of cogs see:
https://gist.github.com/EvieePy/d78c061a4798ae81be9825468fe146be
For a list of exceptions:
https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#exceptions
"""
import discord
import traceback
import sys
from discord.ext import commands
class CommandErrorHandler(commands.Cog):
def __init__(self, bot):
self.bot = bot
@commands.Cog.listener()
async def on_command_error(self, ctx, error):
"""The event triggered when an error is raised while invoking a command.
Parameters
------------
ctx: commands.Context
The context used for command invocation.
error: commands.CommandError
The Exception raised.
"""
# This prevents any commands with local handlers being handled here in on_command_error.
if hasattr(ctx.command, 'on_error'):
return
# This prevents any cogs with an overwritten cog_command_error being handled here.
cog = ctx.cog
if cog:
if cog._get_overridden_method(cog.cog_command_error) is not None:
return
ignored = (commands.CommandNotFound, )
# Allows us to check for original exceptions raised and sent to CommandInvokeError.
# If nothing is found. We keep the exception passed to on_command_error.
error = getattr(error, 'original', error)
# Anything in ignored will return and prevent anything happening.
if isinstance(error, ignored):
return
if isinstance(error, commands.DisabledCommand):
await ctx.send(f'{ctx.command} has been disabled.')
elif isinstance(error, commands.NoPrivateMessage):
try:
await ctx.author.send(f'{ctx.command} can not be used in Private Messages.')
except discord.HTTPException:
pass
# For this error example we check to see where it came from...
elif isinstance(error, commands.BadArgument):
if ctx.command.qualified_name == 'tag list': # Check if the command being invoked is 'tag list'
await ctx.send('I could not find that member. Please try again.')
else:
# All other Errors not returned come here. And we can just print the default TraceBack.
print('Ignoring exception in command {}:'.format(ctx.command), file=sys.stderr)
traceback.print_exception(type(error), error, error.__traceback__, file=sys.stderr)
"""Below is an example of a Local Error Handler for our command do_repeat"""
@commands.command(name='repeat', aliases=['mimic', 'copy'])
async def do_repeat(self, ctx, *, inp: str):
"""A simple command which repeats your input!
Parameters
------------
inp: str
The input you wish to repeat.
"""
await ctx.send(inp)
@do_repeat.error
async def do_repeat_handler(self, ctx, error):
"""A local Error Handler for our command do_repeat.
This will only listen for errors in do_repeat.
The global on_command_error will still be invoked after.
"""
# Check if our required argument inp is missing.
if isinstance(error, commands.MissingRequiredArgument):
if error.param.name == 'inp':
await ctx.send("You forgot to give me input to repeat!")
def setup(bot):
bot.add_cog(CommandErrorHandler(bot))
import discord
import traceback
import sys
from discord.ext import commands
class CommandErrorHandler(commands.Cog):
def __init__(self, bot):
self.bot = bot
@commands.Cog.listener()
async def on_command_error(self, ctx, error):
"""The event triggered when an error is raised while invoking a command.
Parameters
------------
ctx: commands.Context
The context used for command invocation.
error: commands.CommandError
The Exception raised.
"""
if hasattr(ctx.command, 'on_error'):
return
cog = ctx.cog
if cog:
if cog._get_overridden_method(cog.cog_command_error) is not None:
return
ignored = (commands.CommandNotFound, )
error = getattr(error, 'original', error)
if isinstance(error, ignored):
return
if isinstance(error, commands.DisabledCommand):
await ctx.send(f'{ctx.command} has been disabled.')
elif isinstance(error, commands.NoPrivateMessage):
try:
await ctx.author.send(f'{ctx.command} can not be used in Private Messages.')
except discord.HTTPException:
pass
elif isinstance(error, commands.BadArgument):
if ctx.command.qualified_name == 'tag list':
await ctx.send('I could not find that member. Please try again.')
else:
print('Ignoring exception in command {}:'.format(ctx.command), file=sys.stderr)
traceback.print_exception(type(error), error, error.__traceback__, file=sys.stderr)
@commands.command(name='repeat', aliases=['mimic', 'copy'])
async def do_repeat(self, ctx, *, inp: str):
"""A simple command which repeats your input!
Parameters
------------
inp: str
The input you wish to repeat.
"""
await ctx.send(inp)
@do_repeat.error
async def do_repeat_handler(self, ctx, error):
"""A local Error Handler for our command do_repeat.
This will only listen for errors in do_repeat.
The global on_command_error will still be invoked after.
"""
if isinstance(error, commands.MissingRequiredArgument):
if error.param.name == 'inp':
await ctx.send("You forgot to give me input to repeat!")
def setup(bot):
bot.add_cog(CommandErrorHandler(bot))
@modelmat
Copy link

Hey, another example to prevent for the use of on_command_error occurring when __error defined in cogs, use

if hasattr(bot.get_cog(ctx.command.cog_name), '_' + ctx.command.cog_name + '__error'):
        return

Also maybe include __error for in cogs.

@EvieePy
Copy link
Author

EvieePy commented Mar 2, 2018

@modelmat

Hey, another example to prevent for the use of on_command_error occurring when __error defined in cogs, use

Since this is probably a niche thing, and slightly confusing to those who are not familiar with name mangling, I will keep it from the actual examples. Though should someone want to add that to the global handler...

if hasattr(ctx.cog, f'_{ctx.cog.__class__.__name__}__error'):
    ...  # Do whatever...

Would be a much simpler way of doing this.

@ClementJ18
Copy link

The MissingRequiredArgument if statements need to be updated, I'm not sure what changed, whether it was the shift to rewrite or some update of the inspect lib but error.param is a inspect.Parameter object and therefore will always return false in rewrite when compared to a string.

if error.param == 'inp':

has to be replaced by

if error.param.name == 'inp':

@laggycomputer
Copy link

Grammar error on L41.

@jkdz12
Copy link

jkdz12 commented Mar 3, 2019

Since 02/23/2019 this Error Handler doesn't work due the cog changes.
So I suggest you to updating:

    @commands.Cog.listener()
    async def on_command_error(self, ctx, error):
class CommandErrorHandler(commands.Cog):

@fleesu
Copy link

fleesu commented Mar 9, 2019

It's an easter egg!

@Moire9
Copy link

Moire9 commented Aug 10, 2020

What is this licensed under?

@TriHydera
Copy link

Grammar error on L41.

That's try:

@justanothernoob4648
Copy link

The printing default traceback thing doesn't work

Copy link

ghost commented Oct 10, 2020

The printing default traceback thing doesn't work

Yeah doesn't work me either

@tomlin7
Copy link

tomlin7 commented Oct 27, 2020

@hello.error
async def hello_error(self, ctx, error):

is it the right way of having arguments

@Shri2007
Copy link

mine not working

Copy link

ghost commented Mar 7, 2021

mine not working

are you gonna give an error? or say what it is doing? or show your source so people can see what you messed up?

@MrKomodoDragon
Copy link

could this possibly be updated because command.has_error_handler and cog.has_error_handler exists?

@frogmasta
Copy link

frogmasta commented Apr 27, 2021

Using these, we can just put this in the main on_command_error():

if ctx.command.has_error_handler() or ctx.cog.has_error_handler():
    return

@Daudd
Copy link

Daudd commented Apr 27, 2021

Using these, we can just put this in the main on_command_error():

if ctx.command.has_error_handler or ctx.cog.has_error_handler:
    return

Isn't it should be has_error_handler()?

@benjamonnguyen
Copy link

Does anyone know how to handle this error?
'Forbidden: 403 Forbidden (error code: 50001): Missing Access'

@frogmasta
Copy link

@Daudd yea, you're right. Fixed my code.

@krishna0223
Copy link

how to use this in my bot
i mean how to import this

@ImNimboss
Copy link

@benjamonnguyen You don't have the right permissions to do whatever you're trying to do

@bsod2528
Copy link

bsod2528 commented Oct 5, 2021

how to use this in my bot i mean how to import this

you dont have to import anything to make use of it. just make sure that its in your cogs folder

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment