如何在discord.py的Cogs中全局处理app_command错误?
问题描述
我开发的Discord机器人主要使用Cogs和app_commands,需要一个满足以下两个要求的错误处理器:
- 在聊天中发送消息或响应interaction返回错误提示
- 不在控制台输出大量错误信息,仅输出简单的「某用户尝试使用某命令」或不输出
目前我实现了单命令的错误处理:
@app_commands.command(name="test", description="are u mod") @app_commands.checks.has_permissions(moderate_members=True) async def test(self, interaction: discord.Interaction): await interaction.response.send_message("you are a mod!") @test.error async def test_error(self, interaction: discord.Interaction, error): print(f"{interaction.user} tried to use the `test` command") await interaction.response.send_message("no")
但问题是每个管理员命令都要创建对应的错误处理函数,我需要一个全局错误处理器,在任何「缺少管理员权限」检查失败时执行上述逻辑。
我尝试过以下全局错误处理代码:
@bot.tree.error async def on_app_command_error(interaction: discord.Interaction, error: app_commands.AppCommandError): if isinstance(error, app_commands.CommandOnCooldown): return await interaction.response.send_message(error, ephemeral = True) elif isinstance(error, app_commands.BotMissingPermissions): return await interaction.response.send_message(error, ephemeral = True) else: await interaction.response.send_message("An error occurred!", ephemeral = True) raise error
但它仅能返回通用错误提示,无法匹配具体错误类型,且仍会在控制台输出大量错误信息,不满足我的需求。
我的机器人基本结构如下:
main.py
bot = commands.Bot(command_prefix='!', intents=discord.Intents.all()) @bot.event async def on_ready(): print(f'{bot.user} has connected to Discord!') try: synced = await bot.tree.sync() print(f"Synced {len(synced)} command(s)") except Exception as e: print(e) async def load_cogs(): for file in os.listdir('./cogs'): if file.endswith('.py'): await bot.load_extension(f'cogs.{file[:-3]}') asyncio.run(load_cogs()) bot.run(os.getenv('bot_key'))
examplecog.py
class example(commands.Cog): def __init__(self, bot): self.bot = bot @commands.Cog.listener() async def on_ready(self): print(self.__class__.__name__ + " cog loaded") @app_commands.command(name="test", description="are u mod") @app_commands.checks.has_permissions(moderate_members=True) async def test(self, interaction: discord.Interaction): await interaction.response.send_message("you are a mod!") async def example(bot): await bot.add_cog(errors(bot))
解决方案
要实现满足需求的全局错误处理器,需精准匹配权限错误类型,同时避免抛出错误导致控制台输出冗余信息,具体实现如下:
1. 精准匹配错误类型
当@app_commands.checks.has_permissions检查失败时,抛出的是app_commands.MissingPermissions错误(用户缺少权限),而非通用错误。需区分该类型与BotMissingPermissions(机器人缺少权限)。
2. 编写全局错误处理函数
修改@bot.tree.error装饰的全局处理函数,针对性处理各类错误,且不抛出错误:
@bot.tree.error async def on_app_command_error(interaction: discord.Interaction, error: app_commands.AppCommandError): # 用户缺少权限的处理逻辑 if isinstance(error, app_commands.MissingPermissions): print(f"{interaction.user} tried to use `{interaction.command.name}` (missing required permissions)") await interaction.response.send_message("你没有使用该命令的权限!", ephemeral=True) return # 机器人缺少权限的处理逻辑 elif isinstance(error, app_commands.BotMissingPermissions): await interaction.response.send_message("我没有执行该操作的权限,请检查我的角色设置!", ephemeral=True) return # 命令冷却的处理逻辑 elif isinstance(error, app_commands.CommandOnCooldown): await interaction.response.send_message(f"命令冷却中,请等待{error.retry_after:.1f}秒后再试", ephemeral=True) return # 其他未定义错误的处理 print(f"Unknown error from {interaction.user} using `{interaction.command.name}`: {type(error).__name__}") await interaction.response.send_message("发生了未知错误!", ephemeral=True)
3. 封装到Cog(推荐)
若想将错误逻辑独立封装,创建cogs/errors.py文件:
import discord from discord import app_commands from discord.ext import commands class Errors(commands.Cog): def __init__(self, bot): self.bot = bot self.bot.tree.error(coro=self.on_app_command_error) async def on_app_command_error(self, interaction: discord.Interaction, error: app_commands.AppCommandError): if isinstance(error, app_commands.MissingPermissions): print(f"{interaction.user} tried to use `{interaction.command.name}` (missing permissions)") await interaction.response.send_message("你没有权限使用这个命令!", ephemeral=True) return elif isinstance(error, app_commands.BotMissingPermissions): await interaction.response.send_message("我缺少执行该操作的权限,请检查我的角色权限!", ephemeral=True) return elif isinstance(error, app_commands.CommandOnCooldown): await interaction.response.send_message(f"命令正在冷却,{error.retry_after:.1f}秒后再试", ephemeral=True) return print(f"Error from {interaction.user} using `{interaction.command.name}`: {type(error).__name__}") await interaction.response.send_message("出现了未知错误", ephemeral=True) async def setup(bot): await bot.add_cog(Errors(bot))
只要该文件放在./cogs目录下,main.py的load_cogs函数会自动加载。
关键注意事项
- 不要在处理函数中使用
raise error,否则会触发Discord.py输出完整错误堆栈,违背“不输出大量错误信息”的需求。 - 使用
ephemeral=True可让错误提示仅对触发用户可见,避免频道刷屏。 - 通过
interaction.command.name自动获取命令名称,无需硬编码,适配所有命令。
内容的提问来源于stack exchange,提问作者Imaginary
相关产品推荐
相关产品推荐

