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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 12:45:50