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

使用discord.ui分页帮助菜单成功切换却触发交互失败错误

问题描述

开发了带分页功能的Embed帮助菜单,切换页面时内容能成功切换,但Embed下方会显示“This interaction failed”错误。已尝试使用interaction.response.defer()和ctx.defer()延迟交互,但问题仍未解决,控制台无其他错误信息。

相关代码:

class HelpMenu(View):
    try:

        def __init__(self, ctx, data):
            super().__init__()

            self.ctx: commands.Context = ctx
            self.data = data
            self.current_page = 0
            self.per_page = 5
            self.timeout = None
            self.message = None

        async def show_page(self):
            embed = discord.Embed(
                title="Help",
                description="List of available commands",
                color=discord.Color.blurple(),
            )
            embed.set_footer(
                text=f"Page {self.current_page + 1}/{self.get_max_pages()}"
            )

            start_index = self.current_page * self.per_page
            end_index = start_index + self.per_page
            for name, value in self.data[start_index:end_index]:
                embed.add_field(name=name, value=value, inline=False)

            if self.message is None:
                self.message = await self.ctx.send(embed=embed, view=self)
            else:
                await self.message.edit(embed=embed)

        def get_max_pages(self):
            return (len(self.data) + self.per_page - 1) // self.per_page

        @discord.ui.button(label="↩", style=discord.ButtonStyle.primary)
        async def previous_page(
            self, button: discord.ui.Button, interaction: discord.Interaction
        ):
            if self.current_page > 0:
                self.current_page -= 1
                await self.show_page()
            await self.ctx.defer()
            await interaction.response.defer()

        @discord.ui.button(label="↪", style=discord.ButtonStyle.primary)
        async def next_page(
            self, button: discord.ui.Button, interaction: discord.Interaction
        ):
            if self.current_page < self.get_max_pages() - 1:
                self.current_page += 1
                await self.show_page()
            await self.ctx.defer()
            await interaction.response.defer()

    except Exception as e:
        print(e)

@client.command(description="Shows this embed.")
async def help(ctx):
    try:
        commands_list = client.commands
        data = [(command.name, command.description) for command in commands_list]
        menu = HelpMenu(ctx, data)
        await menu.show_page()
    except Exception as e:
        print(e)
问题原因与修复方案

1. 错误的交互响应逻辑

按钮回调中同时调用ctx.defer()和interaction.response.defer()属于重复响应:ctx.defer()是针对命令的延迟响应,不适用于按钮交互场景;双重defer会让Discord无法正确识别交互状态,从而触发失败提示。

另外,修改消息后必须对交互请求给出明确响应,确保Discord收到处理反馈。

2. 不合理的异常捕获范围

将整个HelpMenu类包裹在try-except中,会干扰类方法(尤其是按钮回调)的正常注册,导致Discord无法识别按钮交互逻辑。

修复后的代码

class HelpMenu(View):
    def __init__(self, ctx, data):
        super().__init__()

        self.ctx: commands.Context = ctx
        self.data = data
        self.current_page = 0
        self.per_page = 5
        self.timeout = None
        self.message = None

    async def show_page(self):
        embed = discord.Embed(
            title="Help",
            description="List of available commands",
            color=discord.Color.blurple(),
        )
        embed.set_footer(
            text=f"Page {self.current_page + 1}/{self.get_max_pages()}"
        )

        start_index = self.current_page * self.per_page
        end_index = start_index + self.per_page
        for name, value in self.data[start_index:end_index]:
            embed.add_field(name=name, value=value, inline=False)

        if self.message is None:
            self.message = await self.ctx.send(embed=embed, view=self)
        else:
            await self.message.edit(embed=embed)

    def get_max_pages(self):
        return (len(self.data) + self.per_page - 1) // self.per_page

    @discord.ui.button(label="↩", style=discord.ButtonStyle.primary)
    async def previous_page(
        self, button: discord.ui.Button, interaction: discord.Interaction
    ):
        try:
            if self.current_page > 0:
                self.current_page -= 1
                await self.show_page()
            # 仅对按钮交互给出响应,告知Discord已处理请求
            await interaction.response.defer(ephemeral=False)
        except Exception as e:
            print(e)

    @discord.ui.button(label="↪", style=discord.ButtonStyle.primary)
    async def next_page(
        self, button: discord.ui.Button, interaction: discord.Interaction
    ):
        try:
            if self.current_page < self.get_max_pages() - 1:
                self.current_page += 1
                await self.show_page()
            await interaction.response.defer(ephemeral=False)
        except Exception as e:
            print(e)

@client.command(description="Shows this embed.")
async def help(ctx):
    try:
        commands_list = client.commands
        data = [(command.name, command.description) for command in commands_list]
        menu = HelpMenu(ctx, data)
        await menu.show_page()
    except Exception as e:
        print(e)

核心修改点

  • 移除包裹整个类的try-except,改为在按钮回调内部捕获异常,避免干扰方法注册。
  • 删除ctx.defer(),仅保留interaction.response.defer()处理按钮交互的响应需求。
  • 确保每次按钮点击后都明确响应交互请求,避免Discord因超时未收到反馈而提示失败。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 00:27:07