Discord.py重启后消息按钮失效,点击提示interaction failed
问题原因
机器人重启后,此前消息中的按钮触发“interaction failed”,核心原因是临时创建的View在机器人重启后丢失了回调关联。Discord会将按钮交互请求发送给机器人,但此时机器人内存中已无之前定义的button_callback引用,导致无法处理交互。
修复方案
要实现按钮跨重启可用,必须使用持久化视图,具体操作如下:
1. 定义持久化View类
将按钮与回调逻辑封装为继承discord.ui.View的类,并设置timeout=None(永久不超时):
import discord import asyncio class TicketView(discord.ui.View): def __init__(self, guild): super().__init__(timeout=None) self.guild = guild # 提前获取角色,避免重复查询 self.dropper_role = discord.utils.get(guild.roles, id=1003171723207774218) self.top_dropper_role = discord.utils.get(guild.roles, id=1004989656137465917) @discord.ui.button(label="Ready to start buying?", style=discord.ButtonStyle.green) async def ticket_button(self, interaction: discord.Interaction, button: discord.ui.Button): await interaction.response.send_message("Creating channel...", ephemeral=True) await asyncio.sleep(3) # 配置频道权限 overwrites = { self.guild.default_role: discord.PermissionOverwrite(view_channel=False), interaction.user: discord.PermissionOverwrite(view_channel=True), self.guild.me: discord.PermissionOverwrite(view_channel=True), self.dropper_role: discord.PermissionOverwrite(view_channel=True), self.top_dropper_role: discord.PermissionOverwrite(view_channel=True) } # 创建工单频道 chan = await ticket_category.create_text_channel( f"ticket-{interaction.user.name.lower()}", overwrites=overwrites ) # 更新提示消息 await interaction.edit_original_message( content=f"Channel successfully created {chan.mention}!" ) # 发送频道欢迎嵌入 cc_embed = discord.Embed(title=f"Hello {interaction.user.name}!", color=0x2ecc71) cc_embed.add_field( name="Ready to buy?", value="Type `$dhc` to buy DHC, or `$buygen` to buy Gen! type `$fastpass` to buy fastpass, this allows you to skip all orders! To view prices, type `$prices`!", inline=True ) cc_embed.set_footer(text="discord.gg/dhcc | Rvse's Gen") await chan.send(embed=cc_embed)
2. 机器人启动时注册持久化视图
必须在机器人就绪后注册视图,确保Discord能将交互请求路由到正确回调:
# 假设你的机器人实例为bot @bot.event async def on_ready(): print(f"Logged in as {bot.user}") # 替换为你的服务器ID,注册视图 target_guild = bot.get_guild(你的服务器ID) if target_guild: bot.add_view(TicketView(target_guild))
3. 修改原ticket命令使用持久化视图
原命令中不再临时创建View,直接实例化我们定义的持久化视图:
async def ticket(ctx, *title): guild = ctx.guild # 实例化持久化视图 view = TicketView(guild) # 发送带按钮的消息(可替换为你需要的内容) await ctx.send("点击下方按钮创建工单", view=view)
关键注意事项
- 必须设置
timeout=None,否则视图会在默认180秒后自动失效,即使机器人不重启也无法交互。 - 机器人重启后必须重新注册所有持久化视图,因此
on_ready中的注册步骤不可省略。 - 回调必须使用
@discord.ui.button装饰器定义,而非手动赋值button.callback,这是Discord识别持久化交互逻辑的必要条件。
内容的提问来源于stack exchange,提问作者PhoenixDKA
相关产品推荐
相关产品推荐

