A Python wrapper for the Discord API forked from discord.py
—
Exception hierarchy and error handling patterns for robust Discord bot development with comprehensive error management capabilities.
Core exception classes and their inheritance structure for handling various Discord API errors.
import nextcord
from nextcord import DiscordException, ClientException, HTTPException
from typing import Optional, Dict, Any, Union, List
import aiohttp
class DiscordException(Exception):
"""Base exception class for all nextcord exceptions.
This is the root exception that all other nextcord exceptions inherit from.
Catching this will catch all nextcord-specific errors.
"""
pass
class ClientException(DiscordException):
"""Exception raised when an operation in the Client fails.
These are usually user errors, such as providing invalid parameters
or attempting operations that are not allowed.
"""
pass
class HTTPException(DiscordException):
"""Exception raised when an HTTP request operation fails.
Attributes
----------
response: aiohttp.ClientResponse
The aiohttp response object.
status: int
The HTTP status code.
code: int
The Discord error code.
text: str
The error message from Discord.
"""
def __init__(self, response: aiohttp.ClientResponse, message: Optional[str]):
self.response = response
self.status = response.status
self.code = 0
self.text = message or ''
if message:
super().__init__(f'{self.status} {self.response.reason} (error code: {self.code}): {self.text}')
else:
super().__init__(f'{self.status} {self.response.reason}')
# Basic error handling example
@bot.event
async def on_command_error(ctx, error):
"""Global error handler for command errors."""
if isinstance(error, nextcord.HTTPException):
if error.status == 403:
await ctx.send("❌ I don't have permission to do that!")
elif error.status == 404:
await ctx.send("❌ That resource was not found.")
else:
await ctx.send(f"❌ An HTTP error occurred: {error.text}")
elif isinstance(error, nextcord.ClientException):
await ctx.send(f"❌ Client error: {str(error)}")
else:
print(f"Unexpected error: {type(error).__name__}: {error}")
await ctx.send("❌ An unexpected error occurred.")
# Specific exception handling
try:
await channel.send("Hello!")
except nextcord.Forbidden:
print("No permission to send messages to this channel")
except nextcord.HTTPException as e:
print(f"HTTP error: {e.status} - {e.text}")
except nextcord.DiscordException:
print("A Discord-related error occurred")Specific HTTP exceptions for different Discord API error conditions.
class Forbidden(HTTPException):
"""Exception raised for 403 Forbidden HTTP responses.
This typically means the bot lacks the necessary permissions
to perform the requested action.
"""
pass
class NotFound(HTTPException):
"""Exception raised for 404 Not Found HTTP responses.
This means the requested resource (user, channel, message, etc.)
does not exist or is not accessible.
"""
pass
class DiscordServerError(HTTPException):
"""Exception raised for 5xx HTTP responses.
These are server-side errors from Discord's API and are
usually temporary.
"""
pass
class RateLimited(HTTPException):
"""Exception raised when being rate limited by Discord.
Attributes
----------
retry_after: float
Number of seconds to wait before retrying.
"""
def __init__(self, response: aiohttp.ClientResponse, message: str, retry_after: float):
super().__init__(response, message)
self.retry_after = retry_after
# Comprehensive error handling
async def safe_send_message(channel, content, **kwargs):
"""Safely send a message with comprehensive error handling."""
try:
return await channel.send(content, **kwargs)
except nextcord.Forbidden:
print(f"No permission to send messages in {channel}")
return None
except nextcord.NotFound:
print(f"Channel {channel.id} not found or deleted")
return None
except nextcord.RateLimited as e:
print(f"Rate limited! Retry after {e.retry_after} seconds")
await asyncio.sleep(e.retry_after)
return await channel.send(content, **kwargs) # Retry once
except nextcord.HTTPException as e:
print(f"HTTP error {e.status}: {e.text}")
return None
except Exception as e:
print(f"Unexpected error: {type(e).__name__}: {e}")
return None
# Guild-specific error handling
async def safe_add_role(member, role, reason=None):
"""Safely add a role to a member."""
try:
await member.add_roles(role, reason=reason)
return True
except nextcord.Forbidden:
print(f"No permission to manage roles for {member}")
return False
except nextcord.NotFound:
print(f"Member {member} or role {role} not found")
return False
except nextcord.HTTPException as e:
if e.code == 50013: # Missing permissions
print(f"Missing permissions to add role {role.name}")
elif e.code == 50025: # Invalid OAuth2 access token
print("Invalid bot token")
else:
print(f"Failed to add role: {e.text}")
return False
# Message-related error handling
async def safe_edit_message(message, **kwargs):
"""Safely edit a message with error handling."""
try:
return await message.edit(**kwargs)
except nextcord.Forbidden:
print("No permission to edit this message")
return None
except nextcord.NotFound:
print("Message not found (may have been deleted)")
return None
except nextcord.HTTPException as e:
if e.code == 50005: # Cannot edit message by another user
print("Cannot edit message from another user")
elif e.code == 50001: # Missing access
print("Missing access to edit message")
else:
print(f"Failed to edit message: {e.text}")
return None
# Voice-related error handling
async def safe_connect_voice(channel):
"""Safely connect to a voice channel."""
try:
return await channel.connect()
except nextcord.ClientException as e:
if "already connected" in str(e).lower():
print("Already connected to a voice channel")
# Get existing connection
return nextcord.utils.get(bot.voice_clients, guild=channel.guild)
else:
print(f"Client error connecting to voice: {e}")
return None
except nextcord.Forbidden:
print(f"No permission to connect to {channel.name}")
return None
except asyncio.TimeoutError:
print("Timeout connecting to voice channel")
return None
except Exception as e:
print(f"Unexpected voice connection error: {e}")
return NoneErrors specific to the command framework and command processing.
from nextcord.ext import commands
class CommandError(DiscordException):
"""Base exception for all command related errors.
This inherits from DiscordException and is the base for all
command framework exceptions.
Attributes
----------
message: Optional[str]
The error message.
"""
def __init__(self, message: Optional[str] = None, *args):
if message is not None:
super().__init__(message, *args)
else:
super().__init__(*args)
class CommandNotFound(CommandError):
"""Exception raised when a command is not found.
This is raised when a user tries to invoke a command
that doesn't exist.
"""
pass
class MissingRequiredArgument(CommandError):
"""Exception raised when a required argument is missing.
Attributes
----------
param: inspect.Parameter
The parameter that was missing.
"""
def __init__(self, param):
self.param = param
super().__init__(f'{param.name} is a required argument that is missing.')
class BadArgument(CommandError):
"""Exception raised when parsing an argument fails.
This is typically raised when a converter fails to convert
the provided argument to the expected type.
"""
pass
class CheckFailure(CommandError):
"""Exception raised when a check fails.
This is raised when a command check (like permissions,
cooldowns, etc.) fails.
"""
pass
class MissingPermissions(CheckFailure):
"""Exception raised when the user lacks required permissions.
Attributes
----------
missing_perms: List[str]
List of missing permission names.
"""
def __init__(self, missing_perms: List[str], *args):
self.missing_perms = missing_perms
missing = [perm.replace('_', ' ').replace('guild', 'server').title() for perm in missing_perms]
if len(missing) > 2:
fmt = '{}, and {}'.format(", ".join(missing[:-1]), missing[-1])
else:
fmt = ' and '.join(missing)
message = f'You are missing {fmt} permission(s) to run this command.'
super().__init__(message, *args)
class BotMissingPermissions(CheckFailure):
"""Exception raised when the bot lacks required permissions.
Attributes
----------
missing_perms: List[str]
List of missing permission names.
"""
def __init__(self, missing_perms: List[str], *args):
self.missing_perms = missing_perms
missing = [perm.replace('_', ' ').replace('guild', 'server').title() for perm in missing_perms]
if len(missing) > 2:
fmt = '{}, and {}'.format(", ".join(missing[:-1]), missing[-1])
else:
fmt = ' and '.join(missing)
message = f'Bot requires {fmt} permission(s) to run this command.'
super().__init__(message, *args)
class CommandOnCooldown(CommandError):
"""Exception raised when a command is on cooldown.
Attributes
----------
cooldown: Cooldown
The cooldown that was triggered.
retry_after: float
Number of seconds until the command can be used again.
"""
def __init__(self, cooldown, retry_after: float):
self.cooldown = cooldown
self.retry_after = retry_after
super().__init__(f'You are on cooldown. Try again in {retry_after:.2f}s')
# Command error handling examples
@bot.event
async def on_command_error(ctx: commands.Context, error: commands.CommandError):
"""Global command error handler."""
# Ignore command not found errors
if isinstance(error, commands.CommandNotFound):
return
# Handle missing arguments
elif isinstance(error, commands.MissingRequiredArgument):
embed = nextcord.Embed(
title="❌ Missing Argument",
description=f"Missing required argument: `{error.param.name}`",
color=nextcord.Color.red()
)
embed.add_field(
name="Usage",
value=f"`{ctx.prefix}{ctx.command.qualified_name} {ctx.command.signature}`",
inline=False
)
await ctx.send(embed=embed)
# Handle bad arguments (conversion failures)
elif isinstance(error, commands.BadArgument):
embed = nextcord.Embed(
title="❌ Invalid Argument",
description=str(error),
color=nextcord.Color.red()
)
await ctx.send(embed=embed)
# Handle permission errors
elif isinstance(error, commands.MissingPermissions):
embed = nextcord.Embed(
title="❌ Missing Permissions",
description=str(error),
color=nextcord.Color.red()
)
await ctx.send(embed=embed)
elif isinstance(error, commands.BotMissingPermissions):
embed = nextcord.Embed(
title="❌ Bot Missing Permissions",
description=str(error),
color=nextcord.Color.red()
)
await ctx.send(embed=embed)
# Handle cooldowns
elif isinstance(error, commands.CommandOnCooldown):
embed = nextcord.Embed(
title="⏰ Command on Cooldown",
description=f"Please wait {error.retry_after:.1f} seconds before using this command again.",
color=nextcord.Color.orange()
)
await ctx.send(embed=embed, delete_after=error.retry_after)
# Handle other command errors
elif isinstance(error, commands.CommandError):
embed = nextcord.Embed(
title="❌ Command Error",
description=str(error),
color=nextcord.Color.red()
)
await ctx.send(embed=embed)
# Handle HTTP exceptions
elif isinstance(error, nextcord.HTTPException):
if error.status == 403:
embed = nextcord.Embed(
title="❌ Permission Denied",
description="I don't have permission to perform that action.",
color=nextcord.Color.red()
)
elif error.status == 404:
embed = nextcord.Embed(
title="❌ Not Found",
description="The requested resource was not found.",
color=nextcord.Color.red()
)
else:
embed = nextcord.Embed(
title="❌ HTTP Error",
description=f"An error occurred: {error.text}",
color=nextcord.Color.red()
)
await ctx.send(embed=embed)
# Handle unexpected errors
else:
embed = nextcord.Embed(
title="❌ Unexpected Error",
description="An unexpected error occurred. Please try again later.",
color=nextcord.Color.red()
)
await ctx.send(embed=embed)
# Log the error for debugging
print(f"Unexpected error in {ctx.command}: {type(error).__name__}: {error}")
# Command-specific error handling
@bot.command()
async def ban_user(ctx, member: nextcord.Member, *, reason: str = "No reason provided"):
"""Ban a user with proper error handling."""
try:
await member.ban(reason=reason)
embed = nextcord.Embed(
title="🔨 User Banned",
description=f"{member.mention} has been banned.",
color=nextcord.Color.red()
)
embed.add_field(name="Reason", value=reason, inline=False)
embed.set_footer(text=f"Banned by {ctx.author}", icon_url=ctx.author.display_avatar.url)
await ctx.send(embed=embed)
except nextcord.Forbidden:
await ctx.send("❌ I don't have permission to ban this user.")
except nextcord.HTTPException as e:
if e.code == 50013: # Missing permissions
await ctx.send("❌ I cannot ban this user (they may have higher permissions).")
else:
await ctx.send(f"❌ Failed to ban user: {e.text}")
# Converter error handling
class CustomMemberConverter(commands.Converter):
"""Custom member converter with detailed error messages."""
async def convert(self, ctx: commands.Context, argument: str) -> nextcord.Member:
try:
# Try default member conversion
return await commands.MemberConverter().convert(ctx, argument)
except commands.MemberNotFound:
# Provide helpful error message
raise commands.BadArgument(
f"Member '{argument}' not found. "
"Try using their full username, nickname, or mention."
)
@bot.command()
async def userinfo(ctx, member: CustomMemberConverter = None):
"""Get user info with custom converter error handling."""
member = member or ctx.author
embed = nextcord.Embed(title=f"User Info: {member}", color=member.color)
embed.set_thumbnail(url=member.display_avatar.url)
embed.add_field(name="ID", value=member.id, inline=True)
embed.add_field(name="Joined", value=member.joined_at.strftime("%Y-%m-%d"), inline=True)
await ctx.send(embed=embed)Errors specific to slash commands and application commands.
class ApplicationCommandError(DiscordException):
"""Base exception for application command errors."""
pass
class InteractionResponded(ClientException):
"""Exception raised when an interaction has already been responded to.
This occurs when you try to respond to an interaction that has
already received a response.
"""
pass
class InteractionNotResponded(ClientException):
"""Exception raised when an interaction hasn't been responded to.
This occurs when you try to edit or delete an interaction response
that hasn't been sent yet.
"""
pass
class InteractionTimedOut(ClientException):
"""Exception raised when an interaction times out.
Interactions must be responded to within 3 seconds, or they will
time out and become invalid.
"""
pass
# Application command error handling
@bot.event
async def on_application_command_error(interaction: nextcord.Interaction, error: Exception):
"""Global application command error handler."""
if isinstance(error, nextcord.ApplicationCommandError):
# Handle application command specific errors
await handle_app_command_error(interaction, error)
elif isinstance(error, nextcord.InteractionResponded):
print(f"Interaction {interaction.id} already responded to")
return # Can't send response since it's already responded
elif isinstance(error, nextcord.InteractionNotResponded):
try:
embed = nextcord.Embed(
title="❌ Command Error",
description="An error occurred while processing your command.",
color=nextcord.Color.red()
)
await interaction.response.send_message(embed=embed, ephemeral=True)
except:
print(f"Failed to respond to interaction {interaction.id}")
elif isinstance(error, nextcord.Forbidden):
try:
embed = nextcord.Embed(
title="❌ Permission Denied",
description="I don't have permission to perform that action.",
color=nextcord.Color.red()
)
if not interaction.response.is_done():
await interaction.response.send_message(embed=embed, ephemeral=True)
else:
await interaction.followup.send(embed=embed, ephemeral=True)
except:
pass
else:
# Log unexpected errors
print(f"Unexpected application command error: {type(error).__name__}: {error}")
try:
embed = nextcord.Embed(
title="❌ Unexpected Error",
description="An unexpected error occurred.",
color=nextcord.Color.red()
)
if not interaction.response.is_done():
await interaction.response.send_message(embed=embed, ephemeral=True)
else:
await interaction.followup.send(embed=embed, ephemeral=True)
except:
pass
async def handle_app_command_error(interaction: nextcord.Interaction, error: nextcord.ApplicationCommandError):
"""Handle application command specific errors."""
embed = nextcord.Embed(
title="❌ Command Error",
description=str(error),
color=nextcord.Color.red()
)
try:
if not interaction.response.is_done():
await interaction.response.send_message(embed=embed, ephemeral=True)
else:
await interaction.followup.send(embed=embed, ephemeral=True)
except nextcord.InteractionResponded:
# Already responded, try followup
try:
await interaction.followup.send(embed=embed, ephemeral=True)
except:
pass
# Safe interaction response helper
async def safe_interaction_response(
interaction: nextcord.Interaction,
content: str = None,
embed: nextcord.Embed = None,
ephemeral: bool = False,
**kwargs
):
"""Safely respond to an interaction with error handling."""
try:
if not interaction.response.is_done():
await interaction.response.send_message(
content=content,
embed=embed,
ephemeral=ephemeral,
**kwargs
)
else:
await interaction.followup.send(
content=content,
embed=embed,
ephemeral=ephemeral,
**kwargs
)
return True
except nextcord.InteractionResponded:
print(f"Interaction {interaction.id} already responded to")
return False
except nextcord.InteractionTimedOut:
print(f"Interaction {interaction.id} timed out")
return False
except nextcord.HTTPException as e:
print(f"HTTP error responding to interaction: {e.status} - {e.text}")
return False
except Exception as e:
print(f"Unexpected error responding to interaction: {e}")
return False
# Slash command with comprehensive error handling
@bot.slash_command(description="Kick a member from the server")
async def kick_member(
interaction: nextcord.Interaction,
member: nextcord.Member,
reason: str = "No reason provided"
):
"""Kick command with proper error handling."""
# Check permissions
if not interaction.user.guild_permissions.kick_members:
embed = nextcord.Embed(
title="❌ Missing Permissions",
description="You need 'Kick Members' permission to use this command.",
color=nextcord.Color.red()
)
await safe_interaction_response(interaction, embed=embed, ephemeral=True)
return
# Check if bot can kick the member
if member.top_role >= interaction.guild.me.top_role:
embed = nextcord.Embed(
title="❌ Cannot Kick",
description="I cannot kick this member (they have equal or higher role).",
color=nextcord.Color.red()
)
await safe_interaction_response(interaction, embed=embed, ephemeral=True)
return
# Check if user can kick the member
if member.top_role >= interaction.user.top_role and interaction.user != interaction.guild.owner:
embed = nextcord.Embed(
title="❌ Cannot Kick",
description="You cannot kick this member (they have equal or higher role).",
color=nextcord.Color.red()
)
await safe_interaction_response(interaction, embed=embed, ephemeral=True)
return
try:
# Attempt to kick the member
await member.kick(reason=f"{reason} | Kicked by {interaction.user}")
embed = nextcord.Embed(
title="👢 Member Kicked",
description=f"{member.mention} has been kicked from the server.",
color=nextcord.Color.orange()
)
embed.add_field(name="Reason", value=reason, inline=False)
embed.set_footer(text=f"Kicked by {interaction.user}", icon_url=interaction.user.display_avatar.url)
await safe_interaction_response(interaction, embed=embed)
except nextcord.Forbidden:
embed = nextcord.Embed(
title="❌ Permission Denied",
description="I don't have permission to kick this member.",
color=nextcord.Color.red()
)
await safe_interaction_response(interaction, embed=embed, ephemeral=True)
except nextcord.HTTPException as e:
embed = nextcord.Embed(
title="❌ Kick Failed",
description=f"Failed to kick member: {e.text}",
color=nextcord.Color.red()
)
await safe_interaction_response(interaction, embed=embed, ephemeral=True)Creating custom exceptions for specific bot functionality and domain-specific errors.
# Custom bot-specific exceptions
class BotException(DiscordException):
"""Base exception for custom bot errors."""
pass
class DatabaseError(BotException):
"""Exception raised when database operations fail.
Attributes
----------
operation: str
The database operation that failed.
table: Optional[str]
The table involved in the operation.
"""
def __init__(self, operation: str, table: Optional[str] = None, message: Optional[str] = None):
self.operation = operation
self.table = table
if message:
super().__init__(message)
else:
msg = f"Database {operation} failed"
if table:
msg += f" on table '{table}'"
super().__init__(msg)
class ConfigurationError(BotException):
"""Exception raised for configuration-related errors.
Attributes
----------
setting: str
The configuration setting that caused the error.
"""
def __init__(self, setting: str, message: Optional[str] = None):
self.setting = setting
super().__init__(message or f"Configuration error for setting '{setting}'")
class RateLimitExceeded(BotException):
"""Exception raised when custom rate limits are exceeded.
Attributes
----------
user_id: int
The user who exceeded the rate limit.
command: str
The command that was rate limited.
retry_after: float
Seconds until the user can retry.
"""
def __init__(self, user_id: int, command: str, retry_after: float):
self.user_id = user_id
self.command = command
self.retry_after = retry_after
super().__init__(f"Rate limit exceeded for {command}. Try again in {retry_after:.1f}s")
class InsufficientBalance(BotException):
"""Exception raised when a user has insufficient balance for an operation.
Attributes
----------
user_id: int
The user's ID.
required: int
The required amount.
available: int
The available amount.
"""
def __init__(self, user_id: int, required: int, available: int):
self.user_id = user_id
self.required = required
self.available = available
super().__init__(f"Insufficient balance. Required: {required}, Available: {available}")
class ItemNotFound(BotException):
"""Exception raised when a requested item is not found.
Attributes
----------
item_type: str
The type of item (e.g., 'user', 'guild', 'item').
item_id: Union[int, str]
The ID or name of the item.
"""
def __init__(self, item_type: str, item_id: Union[int, str]):
self.item_type = item_type
self.item_id = item_id
super().__init__(f"{item_type.title()} '{item_id}' not found")
# Custom error handler for bot-specific errors
class BotErrorHandler:
"""Centralized error handler for custom bot errors."""
def __init__(self, bot):
self.bot = bot
self.error_log_channel = None
def set_error_log_channel(self, channel_id: int):
"""Set the channel where errors should be logged."""
self.error_log_channel = channel_id
async def handle_error(
self,
error: Exception,
ctx: Optional[commands.Context] = None,
interaction: Optional[nextcord.Interaction] = None,
user: Optional[nextcord.User] = None
):
"""Handle different types of errors with appropriate responses."""
# Determine response method
if ctx:
respond = lambda **kwargs: ctx.send(**kwargs)
elif interaction:
respond = lambda **kwargs: safe_interaction_response(interaction, **kwargs)
else:
respond = None
# Handle custom errors
if isinstance(error, DatabaseError):
await self._handle_database_error(error, respond)
elif isinstance(error, ConfigurationError):
await self._handle_config_error(error, respond)
elif isinstance(error, RateLimitExceeded):
await self._handle_rate_limit_error(error, respond)
elif isinstance(error, InsufficientBalance):
await self._handle_balance_error(error, respond)
elif isinstance(error, ItemNotFound):
await self._handle_not_found_error(error, respond)
# Handle Discord errors
elif isinstance(error, nextcord.Forbidden):
await self._handle_forbidden_error(error, respond)
elif isinstance(error, nextcord.NotFound):
await self._handle_not_found_discord_error(error, respond)
else:
await self._handle_unexpected_error(error, respond, ctx, interaction)
async def _handle_database_error(self, error: DatabaseError, respond):
"""Handle database errors."""
embed = nextcord.Embed(
title="🗃️ Database Error",
description="A database error occurred. Please try again later.",
color=nextcord.Color.red()
)
if respond:
await respond(embed=embed)
# Log to error channel
await self._log_error("Database Error", str(error))
async def _handle_config_error(self, error: ConfigurationError, respond):
"""Handle configuration errors."""
embed = nextcord.Embed(
title="⚙️ Configuration Error",
description="A configuration issue was detected. Please contact an administrator.",
color=nextcord.Color.red()
)
if respond:
await respond(embed=embed)
await self._log_error("Configuration Error", f"Setting: {error.setting} - {str(error)}")
async def _handle_rate_limit_error(self, error: RateLimitExceeded, respond):
"""Handle custom rate limit errors."""
embed = nextcord.Embed(
title="⏰ Rate Limited",
description=f"You're using commands too quickly! Please wait {error.retry_after:.1f} seconds.",
color=nextcord.Color.orange()
)
if respond:
await respond(embed=embed)
async def _handle_balance_error(self, error: InsufficientBalance, respond):
"""Handle insufficient balance errors."""
embed = nextcord.Embed(
title="💰 Insufficient Balance",
description=f"You need {error.required} but only have {error.available}.",
color=nextcord.Color.red()
)
if respond:
await respond(embed=embed)
async def _handle_not_found_error(self, error: ItemNotFound, respond):
"""Handle item not found errors."""
embed = nextcord.Embed(
title="❓ Not Found",
description=f"{error.item_type.title()} '{error.item_id}' was not found.",
color=nextcord.Color.red()
)
if respond:
await respond(embed=embed)
async def _handle_forbidden_error(self, error: nextcord.Forbidden, respond):
"""Handle Discord forbidden errors."""
embed = nextcord.Embed(
title="❌ Permission Denied",
description="I don't have permission to perform that action.",
color=nextcord.Color.red()
)
if respond:
await respond(embed=embed)
async def _handle_not_found_discord_error(self, error: nextcord.NotFound, respond):
"""Handle Discord not found errors."""
embed = nextcord.Embed(
title="❓ Resource Not Found",
description="The requested Discord resource was not found.",
color=nextcord.Color.red()
)
if respond:
await respond(embed=embed)
async def _handle_unexpected_error(
self,
error: Exception,
respond,
ctx: Optional[commands.Context],
interaction: Optional[nextcord.Interaction]
):
"""Handle unexpected errors."""
embed = nextcord.Embed(
title="❌ Unexpected Error",
description="An unexpected error occurred. The developers have been notified.",
color=nextcord.Color.red()
)
if respond:
await respond(embed=embed)
# Log detailed error information
error_info = {
'type': type(error).__name__,
'message': str(error),
'command': ctx.command.name if ctx else None,
'interaction': interaction.data.get('name') if interaction else None,
'user': (ctx.author.id if ctx else interaction.user.id if interaction else None),
'guild': (ctx.guild.id if ctx and ctx.guild else interaction.guild.id if interaction and interaction.guild else None)
}
await self._log_error("Unexpected Error", str(error_info))
async def _log_error(self, title: str, description: str):
"""Log error to designated channel."""
if not self.error_log_channel:
return
channel = self.bot.get_channel(self.error_log_channel)
if not channel:
return
embed = nextcord.Embed(
title=f"🚨 {title}",
description=f"```\n{description}\n```",
color=nextcord.Color.red(),
timestamp=datetime.now()
)
try:
await channel.send(embed=embed)
except:
pass # Silently fail if we can't log
# Initialize error handler
error_handler = BotErrorHandler(bot)
error_handler.set_error_log_channel(ERROR_LOG_CHANNEL_ID)
# Usage in commands
@bot.command()
async def buy_item(ctx, item_name: str):
"""Buy an item with comprehensive error handling."""
try:
# Get user data
user_data = await get_user_data(ctx.author.id)
if not user_data:
raise ItemNotFound("user", ctx.author.id)
# Get item data
item = await get_item_by_name(item_name)
if not item:
raise ItemNotFound("item", item_name)
# Check balance
if user_data['balance'] < item['price']:
raise InsufficientBalance(ctx.author.id, item['price'], user_data['balance'])
# Process purchase
await process_purchase(ctx.author.id, item['id'])
embed = nextcord.Embed(
title="🛒 Purchase Successful",
description=f"You bought {item['name']} for {item['price']} coins!",
color=nextcord.Color.green()
)
await ctx.send(embed=embed)
except BotException as e:
# Handle custom bot errors
await error_handler.handle_error(e, ctx=ctx)
except Exception as e:
# Handle unexpected errors
await error_handler.handle_error(e, ctx=ctx)
# Global error handlers using the error handler
@bot.event
async def on_command_error(ctx: commands.Context, error: commands.CommandError):
"""Enhanced global command error handler."""
await error_handler.handle_error(error, ctx=ctx)
@bot.event
async def on_application_command_error(interaction: nextcord.Interaction, error: Exception):
"""Enhanced application command error handler."""
await error_handler.handle_error(error, interaction=interaction)This comprehensive documentation covers all aspects of nextcord's error handling system, providing developers with robust tools for managing exceptions and creating reliable Discord bot applications with proper error recovery mechanisms.
Install with Tessl CLI
npx tessl i tessl/pypi-nextcord