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

discord.py使用Components按钮分配角色失败提示交互失败求助

问题排查与修复方案

核心问题原因

你的代码存在以下几个直接导致报错的问题:

  • 库初始化顺序错误:初始化DiscordComponents时传入的是未完成配置的旧client实例,导致组件交互监听异常
  • 未及时响应交互:Discord要求所有组件交互必须在3秒内完成响应,你当前代码接收到按钮点击事件后直接处理角色逻辑,一旦逻辑耗时超过3秒就会触发This interaction failed报错
  • Cog命令注册错误:在Cog类内部不应该使用@client.command()注册命令,应该用Cog专属的@commands.command()装饰器
  • 异常分支未处理:如果要分配的F1R1角色不存在、或者Bot没有分配角色的权限,代码会直接抛出异常终止,也会导致交互失败
  • 代码笔误:超时提示的Embed字段description拼写错误为descprtion,会触发Embed构造异常

修复步骤

  1. 优先调整初始化逻辑,保证DiscordComponents绑定正确的Bot实例
  2. 接收到按钮点击事件后第一时间调用res.respond()或者res.defer()响应交互
  3. 修正Cog命令注册方式,删除重复的角色查找逻辑,增加权限、角色存在性校验
  4. 修正Embed拼写错误

修复后完整代码

import os, json, asyncio, discord, discord.utils
from discord import Embed, Color
from discord.ext import commands
from discord_components import Button, ButtonStyle, Select, SelectOption, ComponentsBot, component
from discord_components.client import DiscordComponents
from discord_components.interaction import Interaction
from discord.utils import get

def get_prefix(client, message):
    with open('prefixes.json','r') as f:
        prefixes = json.load(f)
    return prefixes[str(message.guild.id)]

# 调整初始化顺序,先创建Bot实例再绑定组件
client = commands.Bot(command_prefix = get_prefix,intents=discord.Intents.all(),case_sensitive=True)
DiscordComponents(client)

#----- Class Code for f1r4 -----#
class f1r4(commands.Cog):
    def __init__(self,client):
        self.client = client

    # 修正Cog命令装饰器
    @commands.command()
    async def f1r4(self,ctx):
        embed=discord.Embed(
            title='Floor 1, Room 4',
            url = '',
            description = 'You decide that it\'s time to move on. Maybe, somewhere safer too...',
            color=Color.green())
        embed.set_thumbnail(url='')
        embed.add_field(
            name = 'North',
            value = 'Insert an informative text dump here.',
            inline = True)
        embed.add_field(
            name = 'South',
            value = 'take two boogaloo',
            inline = True)
        embed.add_field(
            name = 'East',
            value = 'Boy howdy don\'t look at the actual descriptions lol',
            inline = True)

        msg = await ctx.send(embed=embed,
                            components=[[
                                Button(label = 'North'),
                                Button(label = 'South'),
                                Button(label = 'East')]])
        
        def check(res):
            return ctx.author == res.user and res.channel == ctx.channel
        
        try:
            res = await client.wait_for('buttonclick', check=check, timeout=30)
        except asyncio.exceptions.TimeoutError:
            tembed = discord.Embed(
                title = 'Need More Time?',
                # 修正拼写错误
                description = 'Try again once you\'ve had a chance to make your decision!',
                color=Color.red())
            await msg.edit(
                embed=tembed,
                components=[
                    Button(style=ButtonStyle.red,
                    label='Command Closed',
                    disabled=True)])
            await asyncio.sleep(5)
            await msg.delete()
            return
        
        if res.component.label == 'North':
            # 第一时间响应交互,避免超时
            await res.defer()
            member = ctx.author
            role = get(ctx.guild.roles, name='F1R1')
            # 增加角色存在校验
            if not role:
                await res.edit_origin(content="未找到对应角色,请联系管理员配置")
                await asyncio.sleep(3)
                await msg.delete()
                return
            if role in member.roles:
                await res.edit_origin(content='You have a character in Room 1!')
                await asyncio.sleep(3)
                await msg.delete()
                return
            else:
                # 增加权限校验
                if not ctx.guild.me.guild_permissions.manage_roles:
                    await res.edit_origin(content="Bot没有分配角色的权限,请联系管理员调整权限")
                    await asyncio.sleep(3)
                    await msg.delete()
                    return
                # 校验Bot角色等级高于要分配的角色
                if role.position >= ctx.guild.me.top_role.position:
                    await res.edit_origin(content="要分配的角色等级高于Bot最高等级,无法分配")
                    await asyncio.sleep(3)
                    await msg.delete()
                    return
                await member.add_roles(role)
                await res.edit_origin(content="角色分配成功")
                await asyncio.sleep(5)
                await msg.delete()
                return
        else:
            await res.defer()
            await asyncio.sleep(1)
            await msg.delete()
            return

def setup(client):
    client.add_cog(f1r4(client))

额外建议

discord-components库已经停止维护多年,完全不兼容当前discord.py 2.0+版本的原生组件API,建议后续直接使用discord.py官方原生的按钮组件功能,稳定性更高。

内容的提问来源于stack exchange,提问作者Kao

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 01:06:04