Skip to content

Instantly share code, notes, and snippets.

@EvieePy
Last active April 3, 2025 19:21
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 Prefix and App commands - discord.py
import logging
import discord
from discord import app_commands
from discord.ext import commands
LOGGER: logging.Logger = logging.getLogger(__name__)
class CommandErrors(commands.Cog):
def __init__(self, bot: commands.Bot) -> None:
# Save the default handlers incase we have to unload this extension...
self.original_command_error = bot.on_command_error
self.original_app_error = bot.tree.on_error
# Assign the new handlers to the bot...
bot.on_command_error = self.on_command_error
bot.tree.on_error = self.on_app_command_error
self.bot = bot
async def cog_unload(self) -> None:
"""Load the original error handlers back into the bot when this Cog unloads."""
self.bot.on_command_error = self.original_command_error
self.bot.tree.on_error = self.original_app_error
async def send(
self,
content: str,
/,
context: commands.Context[commands.Bot] | discord.Interaction[commands.Bot],
ephemeral: bool = True
) -> None:
"""Simple generic method for sending a response.
This method catches and logs discord.HTTPExceptions.
Parameters
----------
content: str
The content to send in the response.
context: commands.Context | discord.Interaction
The context or interaction surrounding the command or app command.
ephemeral: bool
Optional bool indicating whether the repsonse should attempted to be sent ephemerally. Defaults to True.
"""
if isinstance(context, commands.Context):
send = context.send
else:
send = context.response.send_message if not context.response.is_done() else context.followup.send
try:
await send(content=content, ephemeral=ephemeral)
except discord.HTTPException as e:
msg = f'Ignoring HTTPException in %r for %r: %s\n\n'
LOGGER.error(msg, self.send.__name__, self.__class__.__name__, e, exc_info=e)
async def on_command_error(self, ctx: commands.Context[commands.Bot], error: commands.CommandError) -> None:
"""Prefix command error handler."""
# Don't continue if we have a command specific handler...
if ctx.command and ctx.command.has_error_handler():
return
# Don't continue if we have a Cog error handler...
elif ctx.cog and ctx.cog.has_error_handler():
return
error = getattr(error, 'original', error)
ignored = (commands.CommandNotFound, commands.NotOwner)
# Don't continue if the error is in ignored...
if isinstance(error, ignored):
return
# Example of handling some command errors...
# If we don't handle the Exception we log it to console...
elif isinstance(error, commands.NoPrivateMessage):
await self.send("This command can not be used in Private Messages.", context=ctx)
elif isinstance(error, commands.DisabledCommand):
await self.send("This command has been disabled by the owner.", context=ctx)
else:
LOGGER.error("Ignoring exception in command %s", ctx.command, exc_info=error)
async def on_app_command_error(
self,
interaction: discord.Interaction[commands.Bot],
error: app_commands.AppCommandError,
) -> None:
"""AppCommand error handler."""
command = interaction.command
# Default logging if the AppCommand is None...
if command is None:
LOGGER.error("Ignoring exception in command tree", exc_info=error)
return
# Don't continue if we have a command specific handler...
if command.on_error:
return
# Example of responding to an error...
if isinstance(error, app_commands.CommandOnCooldown):
retry_after = error.cooldown.get_retry_after()
await self.send(f"This command is on cooldown. Try again in {retry_after:.2f} seconds...", context=interaction)
else:
# Respond to all unhandled errors as an example... Could be removed to show the default response from Discord.
# All unhandled errors are also logged to console...
await self.send(f"**This application received an unhandled exception:**\n\n{error}", context=interaction)
LOGGER.error('Ignoring exception in command %r', command.name, exc_info=error)
async def setup(bot: commands.Bot) -> None:
await bot.add_cog(CommandErrors(bot))
import logging
import discord
from discord import app_commands
from discord.ext import commands
LOGGER: logging.Logger = logging.getLogger(__name__)
class CommandErrors(commands.Cog):
def __init__(self, bot: commands.Bot) -> None:
self.original_command_error = bot.on_command_error
self.original_app_error = bot.tree.on_error
bot.on_command_error = self.on_command_error
bot.tree.on_error = self.on_app_command_error
self.bot = bot
async def cog_unload(self) -> None:
"""Load the original error handlers back into the bot when this Cog unloads."""
self.bot.on_command_error = self.original_command_error
self.bot.tree.on_error = self.original_app_error
async def send(
self,
content: str,
/,
context: commands.Context[commands.Bot] | discord.Interaction[commands.Bot],
ephemeral: bool = True
) -> None:
"""Simple generic method for sending a response.
Parameters
----------
content: str
The content to send in the response.
context: commands.Context | discord.Interaction
The context or interaction surrounding the command or app command.
ephemeral: bool
Optional bool indicating whether the repsonse should attempted to be sent ephemerally. Defaults to True.
"""
if isinstance(context, commands.Context):
send = context.send
else:
send = context.response.send_message if not context.response.is_done() else context.followup.send
try:
await send(content=content, ephemeral=ephemeral)
except discord.HTTPException as e:
msg = f'Ignoring HTTPException in %r for %r: %s\n\n'
LOGGER.error(msg, self.send.__name__, self.__class__.__name__, e, exc_info=e)
async def on_command_error(self, ctx: commands.Context[commands.Bot], error: commands.CommandError) -> None:
"""Prefix command error handler."""
if ctx.command and ctx.command.has_error_handler():
return
elif ctx.cog and ctx.cog.has_error_handler():
return
error = getattr(error, 'original', error)
ignored = (commands.CommandNotFound, commands.NotOwner)
if isinstance(error, ignored):
return
elif isinstance(error, commands.NoPrivateMessage):
await self.send("This command can not be used in Private Messages.", context=ctx)
elif isinstance(error, commands.DisabledCommand):
await self.send("This command has been disabled by the owner.", context=ctx)
else:
LOGGER.error("Ignoring exception in command %s", ctx.command, exc_info=error)
async def on_app_command_error(
self,
interaction: discord.Interaction[commands.Bot],
error: app_commands.AppCommandError,
) -> None:
"""AppCommand error handler."""
command = interaction.command
if command is None:
LOGGER.error("Ignoring exception in command tree", exc_info=error)
return
if command.on_error:
return
if isinstance(error, app_commands.CommandOnCooldown):
retry_after = error.cooldown.get_retry_after()
await self.send(f"This command is on cooldown. Try again in {retry_after:.2f} seconds...", context=interaction)
else:
await self.send(f"**This application received an unhandled exception:**\n\n{error}", context=interaction)
LOGGER.error('Ignoring exception in command %r', command.name, exc_info=error)
async def setup(bot: commands.Bot) -> None:
await bot.add_cog(CommandErrors(bot))
@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