A Python wrapper for the Discord API forked from discord.py
—
Modern Discord application commands including slash commands, user commands, and message commands with comprehensive interaction handling capabilities.
Modern slash commands that provide a native Discord interface with autocomplete, options, and structured parameters.
import nextcord
from nextcord import SlashOption, OptionType
from nextcord.ext import commands
from typing import Optional, List
def slash_command(
*,
name: Optional[str] = None,
description: Optional[str] = None,
guild_ids: Optional[List[int]] = None,
default_member_permissions: Optional[int] = None,
dm_permission: Optional[bool] = None,
nsfw: bool = False,
force_global: bool = False,
**kwargs
) -> Callable:
"""Decorator to create a slash command.
Parameters
----------
name: Optional[str]
The name of the command. If not provided, uses the function name.
description: Optional[str]
The description of the command. Required for slash commands.
guild_ids: Optional[List[int]]
List of guild IDs where this command should be registered.
default_member_permissions: Optional[int]
Default permissions required to use this command.
dm_permission: Optional[bool]
Whether this command can be used in DMs.
nsfw: bool
Whether this command is NSFW and requires an NSFW channel.
force_global: bool
Whether to force this command to be global even with guild_ids.
"""
...
# Basic slash command example
@bot.slash_command(description="Say hello to someone")
async def hello(interaction: nextcord.Interaction, user: nextcord.Member):
"""A simple slash command that greets a user."""
await interaction.response.send_message(f"Hello, {user.mention}!")
# Slash command with options
@bot.slash_command(description="Get information about a user")
async def userinfo(
interaction: nextcord.Interaction,
user: nextcord.Member = SlashOption(description="The user to get info about"),
show_avatar: bool = SlashOption(description="Show user avatar", default=True)
):
"""Get detailed information about a user."""
embed = nextcord.Embed(
title=f"User Info: {user.display_name}",
color=user.color
)
embed.add_field(name="Username", value=str(user), inline=True)
embed.add_field(name="ID", value=user.id, inline=True)
embed.add_field(name="Joined", value=user.joined_at.strftime("%Y-%m-%d"), inline=True)
if show_avatar:
embed.set_thumbnail(url=user.display_avatar.url)
await interaction.response.send_message(embed=embed)from nextcord import SlashOption, OptionType, ChannelType
from typing import Union
class SlashOption:
"""Represents a slash command option parameter.
Parameters
----------
name: Optional[str]
The name of the option. If not provided, uses parameter name.
description: Optional[str]
The description of the option.
option_type: Optional[OptionType]
The type of the option. Auto-detected from type hints if not provided.
required: Optional[bool]
Whether this option is required. Auto-detected from default values.
default: Any
The default value for this option.
choices: Optional[Union[Dict[str, Union[str, int]], List[Union[str, int]]]]
Predefined choices for this option.
channel_types: Optional[List[ChannelType]]
Valid channel types (for channel options).
min_value: Optional[Union[int, float]]
Minimum value (for number options).
max_value: Optional[Union[int, float]]
Maximum value (for number options).
min_length: Optional[int]
Minimum length (for string options).
max_length: Optional[int]
Maximum length (for string options).
autocomplete: Optional[bool]
Whether this option should use autocomplete.
"""
def __init__(
self,
name: Optional[str] = None,
description: Optional[str] = None,
option_type: Optional[OptionType] = None,
required: Optional[bool] = None,
default: Any = MISSING,
choices: Optional[Union[Dict[str, Union[str, int]], List[Union[str, int]]]] = None,
channel_types: Optional[List[ChannelType]] = None,
min_value: Optional[Union[int, float]] = None,
max_value: Optional[Union[int, float]] = None,
min_length: Optional[int] = None,
max_length: Optional[int] = None,
autocomplete: Optional[bool] = None,
):
...
# Examples of different option types
@bot.slash_command(description="Demonstration of various option types")
async def options_demo(
interaction: nextcord.Interaction,
# String option with choices
color: str = SlashOption(
description="Pick a color",
choices=["red", "green", "blue", "yellow"]
),
# Integer option with min/max
amount: int = SlashOption(
description="Amount (1-100)",
min_value=1,
max_value=100
),
# Optional member parameter
target: Optional[nextcord.Member] = SlashOption(
description="Target member",
default=None
),
# Channel option with specific types
channel: Optional[nextcord.TextChannel] = SlashOption(
description="Text channel",
channel_types=[ChannelType.text, ChannelType.news],
default=None
),
# Boolean option
public: bool = SlashOption(
description="Make response public",
default=False
),
# String with length limits
message: str = SlashOption(
description="Your message",
min_length=1,
max_length=200
)
):
"""Demonstrate various slash option types."""
response = f"Color: {color}, Amount: {amount}, Message: {message}"
if target:
response += f", Target: {target.mention}"
if channel:
response += f", Channel: {channel.mention}"
await interaction.response.send_message(response, ephemeral=not public)class SlashCommandGroup:
"""A group of related slash commands.
Attributes
----------
name: str
The name of the command group.
description: str
The description of the command group.
guild_ids: Optional[List[int]]
Guild IDs where this group should be registered.
"""
def __init__(
self,
name: str,
description: str,
*,
guild_ids: Optional[List[int]] = None,
default_member_permissions: Optional[int] = None,
dm_permission: Optional[bool] = None,
nsfw: bool = False,
):
...
def subcommand(
self,
name: Optional[str] = None,
description: Optional[str] = None,
**kwargs
) -> Callable:
"""Decorator to add a subcommand to this group."""
...
# Command group example
moderation = nextcord.SlashCommandGroup(
name="mod",
description="Moderation commands",
default_member_permissions=nextcord.Permissions(moderate_members=True)
)
@moderation.subcommand(description="Timeout a member")
async def timeout(
interaction: nextcord.Interaction,
member: nextcord.Member = SlashOption(description="Member to timeout"),
duration: int = SlashOption(description="Duration in minutes", min_value=1, max_value=40320),
reason: Optional[str] = SlashOption(description="Reason for timeout", default=None)
):
"""Timeout a member for a specified duration."""
from datetime import datetime, timedelta
until = datetime.utcnow() + timedelta(minutes=duration)
try:
await member.timeout(until=until, reason=reason)
await interaction.response.send_message(
f"⏰ {member.mention} has been timed out for {duration} minutes.",
ephemeral=True
)
except nextcord.Forbidden:
await interaction.response.send_message(
"❌ I don't have permission to timeout this member.",
ephemeral=True
)
@moderation.subcommand(description="Remove timeout from a member")
async def untimeout(
interaction: nextcord.Interaction,
member: nextcord.Member = SlashOption(description="Member to remove timeout from"),
reason: Optional[str] = SlashOption(description="Reason", default=None)
):
"""Remove timeout from a member."""
try:
await member.timeout(until=None, reason=reason)
await interaction.response.send_message(
f"✅ Timeout removed from {member.mention}.",
ephemeral=True
)
except nextcord.Forbidden:
await interaction.response.send_message(
"❌ I don't have permission to remove timeout from this member.",
ephemeral=True
)
# Register the command group
bot.add_application_command(moderation)from nextcord.ext import application_checks
@bot.slash_command(description="Search for items")
async def search(
interaction: nextcord.Interaction,
query: str = SlashOption(
description="Search query",
autocomplete=True
)
):
"""Search command with autocomplete."""
await interaction.response.send_message(f"Searching for: {query}")
@search.on_autocomplete("query")
async def search_autocomplete(interaction: nextcord.Interaction, query: str):
"""Provide autocomplete suggestions for the search command."""
# Example search items
items = [
"Apple", "Banana", "Cherry", "Date", "Elderberry",
"Fig", "Grape", "Honeydew", "Ice cream", "Jackfruit",
"Kiwi", "Lemon", "Mango", "Nectarine", "Orange"
]
# Filter items based on current input
if query:
filtered_items = [item for item in items if query.lower() in item.lower()]
else:
filtered_items = items[:10] # Show first 10 if no query
# Return up to 25 suggestions (Discord's limit)
suggestions = filtered_items[:25]
await interaction.response.send_autocomplete(
{item: item for item in suggestions}
)
# More complex autocomplete with database lookup
@bot.slash_command(description="Get user by name")
async def find_user(
interaction: nextcord.Interaction,
username: str = SlashOption(
description="Username to search for",
autocomplete=True
)
):
"""Find a user by username with autocomplete."""
# Search for the user
user = nextcord.utils.get(interaction.guild.members, name=username)
if user:
await interaction.response.send_message(f"Found user: {user.mention}")
else:
await interaction.response.send_message("User not found.")
@find_user.on_autocomplete("username")
async def username_autocomplete(interaction: nextcord.Interaction, username: str):
"""Provide username autocomplete suggestions."""
# Get guild members matching the query
if username:
matching_members = [
member for member in interaction.guild.members
if username.lower() in member.name.lower()
][:25]
else:
matching_members = interaction.guild.members[:25]
suggestions = {member.name: member.name for member in matching_members}
await interaction.response.send_autocomplete(suggestions)Right-click context menu commands for users and messages.
def user_command(
*,
name: Optional[str] = None,
guild_ids: Optional[List[int]] = None,
default_member_permissions: Optional[int] = None,
dm_permission: Optional[bool] = None,
nsfw: bool = False,
force_global: bool = False,
) -> Callable:
"""Decorator to create a user context menu command.
Parameters
----------
name: Optional[str]
The name of the command. If not provided, uses function name.
guild_ids: Optional[List[int]]
List of guild IDs where this command should be registered.
default_member_permissions: Optional[int]
Default permissions required to use this command.
dm_permission: Optional[bool]
Whether this command can be used in DMs.
nsfw: bool
Whether this command is NSFW.
force_global: bool
Whether to force this command to be global.
"""
...
# User context menu command example
@bot.user_command(name="Get Avatar")
async def get_avatar(interaction: nextcord.Interaction, user: nextcord.Member):
"""Get a user's avatar via right-click menu."""
embed = nextcord.Embed(
title=f"{user.display_name}'s Avatar",
color=user.color or nextcord.Color.blue()
)
embed.set_image(url=user.display_avatar.url)
embed.set_footer(text=f"User ID: {user.id}")
await interaction.response.send_message(embed=embed, ephemeral=True)
@bot.user_command(name="User Info")
async def user_info_context(interaction: nextcord.Interaction, user: nextcord.Member):
"""Get detailed user information via context menu."""
embed = nextcord.Embed(
title=f"User Info: {user.display_name}",
color=user.color or nextcord.Color.blue()
)
embed.add_field(name="Username", value=str(user), inline=True)
embed.add_field(name="ID", value=user.id, inline=True)
embed.add_field(name="Bot", value="Yes" if user.bot else "No", inline=True)
if user.joined_at:
embed.add_field(
name="Joined Server",
value=user.joined_at.strftime("%Y-%m-%d %H:%M UTC"),
inline=True
)
embed.add_field(
name="Account Created",
value=user.created_at.strftime("%Y-%m-%d %H:%M UTC"),
inline=True
)
if user.roles[1:]: # Exclude @everyone
roles = [role.mention for role in user.roles[1:][:10]] # Show first 10 roles
embed.add_field(
name="Roles",
value=", ".join(roles) + ("..." if len(user.roles) > 11 else ""),
inline=False
)
embed.set_thumbnail(url=user.display_avatar.url)
await interaction.response.send_message(embed=embed, ephemeral=True)def message_command(
*,
name: Optional[str] = None,
guild_ids: Optional[List[int]] = None,
default_member_permissions: Optional[int] = None,
dm_permission: Optional[bool] = None,
nsfw: bool = False,
force_global: bool = False,
) -> Callable:
"""Decorator to create a message context menu command.
Parameters
----------
name: Optional[str]
The name of the command. If not provided, uses function name.
guild_ids: Optional[List[int]]
List of guild IDs where this command should be registered.
default_member_permissions: Optional[int]
Default permissions required to use this command.
dm_permission: Optional[bool]
Whether this command can be used in DMs.
nsfw: bool
Whether this command is NSFW.
force_global: bool
Whether to force this command to be global.
"""
...
# Message context menu command examples
@bot.message_command(name="Quote Message")
async def quote_message(interaction: nextcord.Interaction, message: nextcord.Message):
"""Quote a message via right-click menu."""
embed = nextcord.Embed(
description=message.content or "*No text content*",
timestamp=message.created_at,
color=nextcord.Color.blue()
)
embed.set_author(
name=message.author.display_name,
icon_url=message.author.display_avatar.url
)
embed.set_footer(text=f"Originally in #{message.channel.name}")
# Handle attachments
if message.attachments:
embed.add_field(
name="Attachments",
value=f"{len(message.attachments)} file(s)",
inline=True
)
await interaction.response.send_message(embed=embed)
@bot.message_command(name="Message Info")
async def message_info(interaction: nextcord.Interaction, message: nextcord.Message):
"""Get detailed message information."""
embed = nextcord.Embed(
title="Message Information",
color=nextcord.Color.blue()
)
embed.add_field(name="Author", value=message.author.mention, inline=True)
embed.add_field(name="Message ID", value=message.id, inline=True)
embed.add_field(name="Channel", value=message.channel.mention, inline=True)
embed.add_field(
name="Created At",
value=message.created_at.strftime("%Y-%m-%d %H:%M:%S UTC"),
inline=True
)
if message.edited_at:
embed.add_field(
name="Last Edited",
value=message.edited_at.strftime("%Y-%m-%d %H:%M:%S UTC"),
inline=True
)
embed.add_field(
name="Jump to Message",
value=f"[Click here]({message.jump_url})",
inline=True
)
# Content preview
if message.content:
content_preview = message.content[:100] + ("..." if len(message.content) > 100 else "")
embed.add_field(name="Content Preview", value=content_preview, inline=False)
# Attachments
if message.attachments:
attachment_info = []
for attachment in message.attachments[:5]: # Show first 5 attachments
size_kb = attachment.size // 1024
attachment_info.append(f"• {attachment.filename} ({size_kb} KB)")
embed.add_field(
name=f"Attachments ({len(message.attachments)})",
value="\n".join(attachment_info),
inline=False
)
# Reactions
if message.reactions:
reaction_info = []
for reaction in message.reactions[:10]: # Show first 10 reactions
reaction_info.append(f"{reaction.emoji} ({reaction.count})")
embed.add_field(
name="Reactions",
value=" ".join(reaction_info),
inline=False
)
await interaction.response.send_message(embed=embed, ephemeral=True)
@bot.message_command(name="Copy Message ID")
async def copy_message_id(interaction: nextcord.Interaction, message: nextcord.Message):
"""Copy a message ID to clipboard-friendly format."""
await interaction.response.send_message(
f"Message ID: `{message.id}`\n"
f"Jump URL: {message.jump_url}",
ephemeral=True
)Interaction objects and response handling for application commands.
class Interaction:
"""Represents a Discord interaction.
Attributes
----------
id: int
The interaction ID.
application_id: int
The application ID that received this interaction.
type: InteractionType
The type of interaction.
data: Optional[InteractionData]
The interaction data payload.
guild_id: Optional[int]
The guild ID where this interaction was sent from.
channel_id: Optional[int]
The channel ID where this interaction was sent from.
user: Union[User, Member]
The user who invoked this interaction.
token: str
The interaction token.
version: int
The version of interaction.
message: Optional[Message]
The message this interaction is attached to.
locale: Optional[str]
The selected language of the user who invoked this interaction.
guild_locale: Optional[str]
The guild's preferred locale.
"""
@property
def guild(self) -> Optional[Guild]:
"""Optional[Guild]: The guild this interaction was sent from."""
...
@property
def channel(self) -> Optional[Union[GuildChannel, PartialMessageable]]:
"""The channel this interaction was sent from."""
...
@property
def permissions(self) -> Permissions:
"""Permissions: The resolved permissions of the user in the channel."""
...
@property
def response(self) -> InteractionResponse:
"""InteractionResponse: Returns an object responsible for handling responses."""
...
@property
def followup(self) -> Webhook:
"""Webhook: Returns the follow-up webhook for this interaction."""
...
def is_expired(self) -> bool:
"""bool: Whether the interaction is expired and can no longer be responded to."""
...
async def edit_original_message(self, **kwargs) -> InteractionMessage:
"""Edit the original interaction response message."""
...
async def delete_original_message(self) -> None:
"""Delete the original interaction response message."""
...
async def original_message(self) -> InteractionMessage:
"""Fetch the original interaction response message."""
...class InteractionResponse:
"""Handles responding to Discord interactions.
This class is accessed via Interaction.response and provides
methods for sending initial responses to interactions.
"""
async def send_message(
self,
content: Optional[str] = None,
*,
embed: Optional[Embed] = None,
embeds: Optional[List[Embed]] = None,
file: Optional[File] = None,
files: Optional[List[File]] = None,
view: Optional[View] = None,
tts: bool = False,
ephemeral: bool = False,
allowed_mentions: Optional[AllowedMentions] = None,
suppress_embeds: bool = False,
delete_after: Optional[float] = None,
) -> None:
"""Send a message response to the interaction.
Parameters
----------
content: Optional[str]
The message content to send.
embed: Optional[Embed]
An embed to send with the message.
embeds: Optional[List[Embed]]
A list of embeds to send. Maximum of 10.
file: Optional[File]
A file to send with the message.
files: Optional[List[File]]
A list of files to send. Maximum of 10.
view: Optional[View]
A UI view to attach to the message.
tts: bool
Whether the message should be text-to-speech.
ephemeral: bool
Whether the message should be ephemeral (only visible to the user).
allowed_mentions: Optional[AllowedMentions]
Controls which mentions are processed.
suppress_embeds: bool
Whether to suppress embeds in the message.
delete_after: Optional[float]
Delete the message after this many seconds.
"""
...
async def defer(self, *, ephemeral: bool = False, thinking: bool = False) -> None:
"""Defer the interaction response.
This allows you to respond later using followup messages.
Parameters
----------
ephemeral: bool
Whether the deferred response should be ephemeral.
thinking: bool
Whether to show "Bot is thinking..." message.
"""
...
async def edit_message(
self,
content: Optional[str] = MISSING,
*,
embed: Optional[Embed] = MISSING,
embeds: Optional[List[Embed]] = MISSING,
file: Optional[File] = MISSING,
files: Optional[List[File]] = MISSING,
attachments: Optional[List[Attachment]] = MISSING,
view: Optional[View] = MISSING,
allowed_mentions: Optional[AllowedMentions] = MISSING,
delete_after: Optional[float] = None,
) -> None:
"""Edit the message that triggered this interaction.
Note: This is only available for component interactions.
"""
...
async def send_autocomplete(
self,
choices: Dict[str, Union[str, int, float]]
) -> None:
"""Send autocomplete suggestions.
Parameters
----------
choices: Dict[str, Union[str, int, float]]
A dictionary of choices where keys are display names
and values are the actual values to be used.
"""
...
async def send_modal(self, modal: Modal) -> None:
"""Send a modal dialog in response to the interaction.
Parameters
----------
modal: Modal
The modal dialog to send.
"""
...
@property
def is_done(self) -> bool:
"""bool: Whether an initial response has been sent."""
...# Follow-up messages are sent after the initial response
@bot.slash_command(description="Example of follow-up messages")
async def followup_example(interaction: nextcord.Interaction):
"""Demonstrate follow-up message usage."""
# Send initial response
await interaction.response.send_message("Processing your request...")
# Simulate some work
import asyncio
await asyncio.sleep(2)
# Send follow-up message
await interaction.followup.send("Step 1 complete!")
await asyncio.sleep(1)
# Another follow-up
embed = nextcord.Embed(title="Final Result", description="Task completed successfully!")
await interaction.followup.send(embed=embed)
# You can also edit the original message
await interaction.edit_original_message(content="✅ All steps completed!")
@bot.slash_command(description="Example with deferred response")
async def long_task(interaction: nextcord.Interaction):
"""Example of using deferred response for long tasks."""
# Defer the response to give more time
await interaction.response.defer(ephemeral=True)
# Simulate long-running task
import asyncio
await asyncio.sleep(5)
# Send the actual response via followup
embed = nextcord.Embed(
title="Long Task Complete",
description="The task that took 5 seconds has finished!",
color=nextcord.Color.green()
)
await interaction.followup.send(embed=embed)Permission and validation checks for application commands.
from nextcord.ext import application_checks
# Permission-based checks
@application_checks.has_permissions(manage_messages=True)
@bot.slash_command(description="Delete messages")
async def purge(
interaction: nextcord.Interaction,
amount: int = SlashOption(description="Number of messages to delete", min_value=1, max_value=100)
):
"""Delete messages (requires manage_messages permission)."""
deleted = await interaction.channel.purge(limit=amount)
await interaction.response.send_message(
f"Deleted {len(deleted)} messages.",
ephemeral=True
)
# Role-based checks
@application_checks.has_any_role("Admin", "Moderator")
@bot.slash_command(description="Admin only command")
async def admin_command(interaction: nextcord.Interaction):
"""Command only available to users with Admin or Moderator role."""
await interaction.response.send_message("Admin command executed!", ephemeral=True)
# Guild-only check
@application_checks.guild_only()
@bot.slash_command(description="Server only command")
async def server_only(interaction: nextcord.Interaction):
"""This command can only be used in servers, not DMs."""
await interaction.response.send_message(f"Server: {interaction.guild.name}")
# Owner check
@application_checks.is_owner()
@bot.slash_command(description="Bot owner only")
async def owner_only(interaction: nextcord.Interaction):
"""Command only available to the bot owner."""
await interaction.response.send_message("Owner command executed!", ephemeral=True)
# Custom check function
def is_in_voice_channel():
"""Check if user is in a voice channel."""
async def predicate(interaction: nextcord.Interaction) -> bool:
if not interaction.user.voice:
await interaction.response.send_message(
"You must be in a voice channel to use this command!",
ephemeral=True
)
return False
return True
return application_checks.check(predicate)
@is_in_voice_channel()
@bot.slash_command(description="Voice channel required")
async def voice_command(interaction: nextcord.Interaction):
"""Command that requires being in a voice channel."""
channel = interaction.user.voice.channel
await interaction.response.send_message(f"You're in {channel.name}!")from functools import wraps
from nextcord.ext.application_checks import ApplicationCheckFailure
class NotInMaintenanceMode(ApplicationCheckFailure):
"""Custom exception for maintenance mode check."""
pass
def not_in_maintenance():
"""Custom check to prevent command usage during maintenance."""
def decorator(func):
@wraps(func)
async def wrapper(interaction: nextcord.Interaction, *args, **kwargs):
# Check some maintenance flag (could be from database, config, etc.)
maintenance_mode = False # Replace with actual check
if maintenance_mode:
await interaction.response.send_message(
"🔧 Bot is currently in maintenance mode. Please try again later.",
ephemeral=True
)
raise NotInMaintenanceMode("Bot is in maintenance mode")
return await func(interaction, *args, **kwargs)
return wrapper
return decorator
def cooldown_check(rate: int, per: float):
"""Custom cooldown check for application commands."""
def decorator(func):
cooldowns = {}
@wraps(func)
async def wrapper(interaction: nextcord.Interaction, *args, **kwargs):
import time
user_id = interaction.user.id
current_time = time.time()
if user_id in cooldowns:
time_left = cooldowns[user_id] + per - current_time
if time_left > 0:
await interaction.response.send_message(
f"Command on cooldown. Try again in {time_left:.1f} seconds.",
ephemeral=True
)
return
cooldowns[user_id] = current_time
return await func(interaction, *args, **kwargs)
return wrapper
return decorator
# Usage of custom checks
@not_in_maintenance()
@cooldown_check(rate=1, per=30.0) # 1 use per 30 seconds
@bot.slash_command(description="Command with custom checks")
async def custom_checked_command(interaction: nextcord.Interaction):
"""Command with maintenance and cooldown checks."""
await interaction.response.send_message("Command executed successfully!")Comprehensive error handling for application commands.
@bot.event
async def on_application_command_error(interaction: nextcord.Interaction, error: Exception):
"""Global error handler for application commands."""
if isinstance(error, application_checks.MissingPermissions):
missing = ", ".join(error.missing_permissions)
await interaction.response.send_message(
f"❌ You're missing the following permissions: {missing}",
ephemeral=True
)
elif isinstance(error, application_checks.MissingAnyRole):
roles = ", ".join(error.missing_roles)
await interaction.response.send_message(
f"❌ You need one of these roles: {roles}",
ephemeral=True
)
elif isinstance(error, application_checks.NotOwner):
await interaction.response.send_message(
"❌ This command is only available to the bot owner.",
ephemeral=True
)
elif isinstance(error, application_checks.NoPrivateMessage):
await interaction.response.send_message(
"❌ This command cannot be used in direct messages.",
ephemeral=True
)
elif isinstance(error, nextcord.errors.ApplicationInvokeError):
# Handle errors within command execution
original_error = error.original
if isinstance(original_error, nextcord.Forbidden):
await interaction.response.send_message(
"❌ I don't have permission to perform this action.",
ephemeral=True
)
elif isinstance(original_error, nextcord.NotFound):
await interaction.response.send_message(
"❌ The requested resource was not found.",
ephemeral=True
)
else:
# Log unexpected errors
import traceback
print(f"Unexpected error in command: {error}")
traceback.print_exception(type(original_error), original_error, original_error.__traceback__)
if not interaction.response.is_done():
await interaction.response.send_message(
"❌ An unexpected error occurred. Please try again later.",
ephemeral=True
)
else:
# Handle other unexpected errors
print(f"Unhandled application command error: {error}")
if not interaction.response.is_done():
await interaction.response.send_message(
"❌ An error occurred while processing your command.",
ephemeral=True
)
# Command-specific error handling
@bot.slash_command(description="Command with specific error handling")
async def error_prone_command(
interaction: nextcord.Interaction,
user: nextcord.Member = SlashOption(description="Target user")
):
"""Command that demonstrates error handling."""
try:
# Some operation that might fail
await user.send("Hello from the bot!")
await interaction.response.send_message(f"Message sent to {user.mention}!")
except nextcord.Forbidden:
await interaction.response.send_message(
f"❌ I can't send a DM to {user.mention}. They may have DMs disabled.",
ephemeral=True
)
except nextcord.HTTPException as e:
await interaction.response.send_message(
f"❌ Failed to send message: {e}",
ephemeral=True
)
except Exception as e:
await interaction.response.send_message(
"❌ An unexpected error occurred.",
ephemeral=True
)
# Log the error for debugging
import traceback
traceback.print_exc()This comprehensive documentation covers all aspects of nextcord's application command system, providing developers with the knowledge needed to implement modern Discord interactions effectively.
Install with Tessl CLI
npx tessl i tessl/pypi-nextcord