You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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))

原因分析

  1. 异常包装问题:在命令函数内部同步调用check_admin_rights抛出的AppCommandError会被discord.py自动包装为CommandInvokeError,原错误处理器未处理这种包装后的异常,导致无法触发自定义响应。
  2. 交互响应状态问题:直接调用interaction.response.send_message时,若交互已超时或处于已响应状态,该操作会静默失败,仅在控制台输出错误。
  3. 未阻止默认错误传播:错误处理器未终止默认错误处理流程,导致控制台输出原始错误,但自定义响应无法覆盖生效。

解决方案

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 09:33:20