discord.py使用Components按钮分配角色失败提示交互失败求助
问题排查与修复方案
核心问题原因
你的代码存在以下几个直接导致报错的问题:
- 库初始化顺序错误:初始化
DiscordComponents时传入的是未完成配置的旧client实例,导致组件交互监听异常 - 未及时响应交互:Discord要求所有组件交互必须在3秒内完成响应,你当前代码接收到按钮点击事件后直接处理角色逻辑,一旦逻辑耗时超过3秒就会触发
This interaction failed报错 - Cog命令注册错误:在Cog类内部不应该使用
@client.command()注册命令,应该用Cog专属的@commands.command()装饰器 - 异常分支未处理:如果要分配的
F1R1角色不存在、或者Bot没有分配角色的权限,代码会直接抛出异常终止,也会导致交互失败 - 代码笔误:超时提示的Embed字段
description拼写错误为descprtion,会触发Embed构造异常
修复步骤
- 优先调整初始化逻辑,保证DiscordComponents绑定正确的Bot实例
- 接收到按钮点击事件后第一时间调用
res.respond()或者res.defer()响应交互 - 修正Cog命令注册方式,删除重复的角色查找逻辑,增加权限、角色存在性校验
- 修正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
相关产品推荐
相关产品推荐

