discord.py 2.0:Cog中App Command异常未被错误处理器捕获问题
问题描述
项目结构:
- Bot模型定义在
main.py中 - 管理员权限校验实现于
classes/checkouts.py - 两个Cog:
cogs/dice.py(命令Cog)和cogs/errors.py(错误处理器Cog)
当checkouts模块抛出异常时,错误处理器无任何响应,仅控制台输出错误信息,Discord应用端无反馈。
相关代码
main.py
import discord import os from classes.discordclient import DiscordClient from classes.database import DatabaseInterface from classes.checkouts import Checkouts class Client(DiscordClient): def __init__(self) -> None: self.__synced = False super().__init__( command_prefix='$', intents=discord.Intents.all(),) async def on_ready(self) -> None: if not self.__synced: await self.tree.sync() self.__synced = True async def setup_hook(self) -> None: self.__database = DatabaseInterface('roleplay.db') self.__checkouts = Checkouts() for f in os.listdir("./cogs"): if f.endswith(".py"): await self.load_extension("cogs." + f[:-3]) def get_database(self) -> DatabaseInterface: return self.__database def get_checkouts(self) -> Checkouts: return self.__checkouts if __name__ == '__main__': bot = Client() token = open('token') bot.run(token.read(70))
classes/checkouts.py
import discord class Checkouts: '''List of static utils methods, that checks user's unput''' @staticmethod def check_admin_rights(interaction: discord.Interaction) -> None: if interaction.guild.get_role(898307915348332614) not in interaction.user.roles: raise discord.app_commands.AppCommandError('User access denied')
cogs/errors.py
import discord from discord import app_commands from discord.ext import commands import random class CommandErrorHandler(commands.Cog): def __init__(self, bot) -> None: self.bot = bot @commands.Cog.listener("on_app_command_error") async def get_app_command_error(self, interaction: discord.Interaction, error: app_commands.AppCommandError): interaction.response.send_message('An error occured') async def setup(bot): await bot.add_cog(CommandErrorHandler(bot))
原因分析
- 异常包装问题:在命令函数内部同步调用
check_admin_rights抛出的AppCommandError会被discord.py自动包装为CommandInvokeError,原错误处理器未处理这种包装后的异常,导致无法触发自定义响应。 - 交互响应状态问题:直接调用
interaction.response.send_message时,若交互已超时或处于已响应状态,该操作会静默失败,仅在控制台输出错误。 - 未阻止默认错误传播:错误处理器未终止默认错误处理流程,导致控制台输出原始错误,但自定义响应无法覆盖生效。
解决方案
1. 修复错误处理器逻辑
更新cogs/errors.py,处理包装后的异常,并兼容交互响应状态:
import discord from discord import app_commands from discord.ext import commands class CommandErrorHandler(commands.Cog): def __init__(self, bot) -> None: self.bot = bot @commands.Cog.listener("on_app_command_error") async def get_app_command_error(self, interaction: discord.Interaction, error: app_commands.AppCommandError): # 解包获取原始异常 original_error = getattr(error, 'original', error) # 匹配权限不足的异常 error_msg = '你没有执行此命令的权限!' if str(original_error) == 'User access denied' else '发生了一个错误!' # 优先尝试直接响应,失败则使用followup发送消息 try: await interaction.response.send_message(error_msg, ephemeral=True) except discord.InteractionResponded: await interaction.followup.send(error_msg, ephemeral=True) # 阻止默认错误处理,避免重复输出 error.stop() async def setup(bot): await bot.add_cog(CommandErrorHandler(bot))
2. 改用规范的权限校验方式
将权限校验实现为app_commands.check装饰器,让discord.py自动处理异常流程:
修改classes/checkouts.py:
import discord from discord import app_commands class Checkouts: '''权限校验工具类''' @staticmethod def check_admin_rights(): async def predicate(interaction: discord.Interaction): admin_role = interaction.guild.get_role(898307915348332614) if admin_role not in interaction.user.roles: raise app_commands.MissingPermissions(["administrator"]) return True return app_commands.check(predicate)
在命令Cog中使用(以cogs/dice.py为例):
from discord import app_commands from discord.ext import commands from classes.checkouts import Checkouts class DiceCog(commands.Cog): def __init__(self, bot): self.bot = bot @app_commands.command(name="roll", description="掷骰子") @Checkouts.check_admin_rights() async def roll_dice(self, interaction: discord.Interaction): await interaction.response.send_message("掷出了6点!") async def setup(bot): await bot.add_cog(DiceCog(bot))
3. 验证Cog加载正确性
确认main.py的setup_hook方法正确加载了cogs/errors.py,检查文件名拼写、后缀是否为.py。
内容的提问来源于stack exchange,提问作者Not a cat Beaver
相关产品推荐
相关产品推荐

