discord.py斜杠命令中add_reaction等方法失效问题求助
问题描述
近期尝试制作一个通过表情反应切换页面的/help斜杠命令(暂未掌握按钮实现方法),该逻辑在普通前缀命令模式下运行正常,但改为斜杠命令后,add_reaction()、clear_reactions()和remove_reaction()完全无法工作,报错如下:
报错信息
2022-12-02 13:02:23 ERROR discord.app_commands.tree Ignoring exception in command 'help' Traceback (most recent call last): File "C:\Users\human\AppData\Local\Programs\Python\Python310\lib\site-packages\discord\app_commands\commands.py", line 862, in _do_call return await self._callback(interaction, **params) # type: ignore File "c:\Users\human\OneDrive\Documents\EverythingBot\main.py", line 155, in rob await message.add_reaction('⏮') AttributeError: 'NoneType' object has no attribute 'add_reaction' The above exception was the direct cause of the following exception: Traceback (most recent call last): File "C:\Users\human\AppData\Local\Programs\Python\Python310\lib\site-packages\discord\app_commands\tree.py", line 1242, in _call await command._invoke_with_namespace(interaction, namespace) File "C:\Users\human\AppData\Local\Programs\Python\Python310\lib\site-packages\discord\app_commands\commands.py", line 887, in _invoke_with_namespace return await self._do_call(interaction, transformed_values) File "C:\Users\human\AppData\Local\Programs\Python\Python310\lib\site-packages\discord\app_commands\commands.py", line 880, in _do_call raise CommandInvokeError(self, e) from e discord.app_commands.errors.CommandInvokeError: Command 'help' raised an exception: AttributeError: 'NoneType' object has no attribute 'add_reaction' 2022-12-02 13:04:44 ERROR discord.ext.commands.bot Ignoring exception in command help Traceback (most recent call last): File "C:\Users\human\AppData\Local\Programs\Python\Python310\lib\site-packages\discord\ext\commands\core.py", line 229, in wrapped ret = await coro(*args, **kwargs) File "c:\Users\human\OneDrive\Documents\EverythingBot\main.py", line 105, in help await message.clear_reactions() File "C:\Users\human\AppData\Local\Programs\Python\Python310\lib\site-packages\discord\message.py", line 1154, in clear_reactions await self._state.http.clear_reactions(self.channel.id, self.id) File "C:\Users\human\AppData\Local\Programs\Python\Python310\lib\site-packages\discord\http.py", line 738, in request raise Forbidden(response, data) discord.errors.Forbidden: 403 Forbidden (error code: 50003): Cannot execute action on a DM channel raise CommandInvokeError(exc) from exc discord.ext.commands.errors.CommandInvokeError: Command raised an exception: Forbidden: 403 Forbidden (error code: 50003): Cannot execute action on a DM channel
当前代码
@client.tree.command(name = "help", description = "Display the bots commands") async def rob(interaction: discord.Interaction): page1 = discord.Embed ( title = 'Fun Commands:', description = '', colour = discord.Colour(0x00ffff) ) page1.add_field(name = "Meme", value = "Sends a random meme.", inline=False) page1.add_field(name = "8ball [question]", value = "Ask the 8 ball a question!", inline=False) page1.add_field(name = "Hi", value = "Say hi to the bot!", inline=False) page1.add_field(name = "Die", value = "Sends randomly selected quotes of last words.", inline=False) page1.add_field(name = "Ping", value = "Returns your ping.", inline=False) page1.add_field(name = "ABC", value = "Displays the alphabet!", inline=False) page1.add_field(name = "Pi", value = "Displays the first 100 digits of pi.") page2 = discord.Embed ( title = 'Economy Commands:', description = '', colour = discord.Colour(0x00ffff) ) page3 = discord.Embed ( title = 'Moderation Commands:', description = '', colour = discord.Colour(0x00ffff) ) page3.add_field(name = "kick [user]", value = "Kicks a specified user.") page3.add_field(name = "ban [user]", value = "Bans a specified user.") page3.add_field(name = "unban [user]", value = "Unbans a specified user.") page3.add_field(name = "clear [number]", value = "Clears a specified number of messages.") page4 = discord.Embed ( title = "Support Server:", description = "", colour = discord.Colour(0x00ffff) ) pages = [page1, page2, page3, page4] message = await interaction.response.send_message(embed = page1) await message.add_reaction('⏮') await message.add_reaction('◀') await message.add_reaction('▶') await message.add_reaction('⏭') def check(reaction, user): return user == interaction.user i = 0 reaction = None while True: if str(reaction) == '⏮': i = 0 await message.edit(embed = pages[i]) elif str(reaction) == '◀': if i > 0: i -= 1 await message.edit(embed = pages[i]) elif str(reaction) == '▶': if i < 3: i += 1 await message.edit(embed = pages[i]) elif str(reaction) == '⏭': i = 3 await message.edit(embed = pages[i]) try: reaction, user = await client.wait_for('reaction_add', timeout = 120.0, check = check) await message.remove_reaction(reaction, user) except: break await message.clear_reactions()
问题原因及修复方案
1. AttributeError: 'NoneType' object has no attribute 'add_reaction'
斜杠命令的interaction.response.send_message()默认不返回消息对象,需要添加wait=True参数,让方法等待消息发送完成后返回对应的Message实例,否则message变量会是None,自然无法调用add_reaction。
2. Forbidden: 403 Forbidden (error code: 50003): Cannot execute action on a DM channel
Discord不允许在DM频道中对斜杠命令的消息进行表情反应操作,因此需要先判断当前频道是否为服务器频道,若为DM则提示用户无法使用该功能。
3. 额外优化
- 斜杠命令的消息若设置为
ephemeral=True(仅自己可见),同样无法添加表情反应,需确保发送公开消息(默认ephemeral=False)。 - 可以添加权限判断,确保bot有添加表情反应的权限。
修复后的完整代码
@client.tree.command(name="help", description="Display the bots commands") async def rob(interaction: discord.Interaction): # 检查是否在服务器频道中 if not isinstance(interaction.channel, discord.GuildChannel): await interaction.response.send_message("此命令仅能在服务器频道中使用!", ephemeral=True) return page1 = discord.Embed( title='Fun Commands:', description='', colour=discord.Colour(0x00ffff) ) page1.add_field(name="Meme", value="Sends a random meme.", inline=False) page1.add_field(name="8ball [question]", value="Ask the 8 ball a question!", inline=False) page1.add_field(name="Hi", value="Say hi to the bot!", inline=False) page1.add_field(name="Die", value="Sends randomly selected quotes of last words.", inline=False) page1.add_field(name="Ping", value="Returns your ping.", inline=False) page1.add_field(name="ABC", value="Displays the alphabet!", inline=False) page1.add_field(name="Pi", value="Displays the first 100 digits of pi.") page2 = discord.Embed( title='Economy Commands:', description='', colour=discord.Colour(0x00ffff) ) page3 = discord.Embed( title='Moderation Commands:', description='', colour=discord.Colour(0x00ffff) ) page3.add_field(name="kick [user]", value="Kicks a specified user.") page3.add_field(name="ban [user]", value="Bans a specified user.") page3.add_field(name="unban [user]", value="Unbans a specified user.") page3.add_field(name="clear [number]", value="Clears a specified number of messages.") page4 = discord.Embed( title="Support Server:", description="", colour=discord.Colour(0x00ffff) ) pages = [page1, page2, page3, page4] # 添加wait=True获取消息对象 message = await interaction.response.send_message(embed=page1, wait=True) await message.add_reaction('⏮') await message.add_reaction('◀') await message.add_reaction('▶') await message.add_reaction('⏭') def check(reaction, user): return user == interaction.user and str(reaction.emoji) in ['⏮', '◀', '▶', '⏭'] i = 0 reaction = None while True: if str(reaction) == '⏮': i = 0 await message.edit(embed=pages[i]) elif str(reaction) == '◀': if i > 0: i -= 1 await message.edit(embed=pages[i]) elif str(reaction) == '▶': if i < len(pages)-1: # 改为动态获取页数,避免硬编码3 i += 1 await message.edit(embed=pages[i]) elif str(reaction) == '⏭': i = len(pages)-1 await message.edit(embed=pages[i]) try: reaction, user = await client.wait_for('reaction_add', timeout=120.0, check=check) await message.remove_reaction(reaction, user) except: break await message.clear_reactions()
关键修改点说明
- 增加了服务器频道判断,避免在DM中执行操作。
send_message添加wait=True参数,正确获取消息对象。- 优化了页数判断逻辑,从硬编码
3改为len(pages)-1,方便后续增减页面。 - 完善了
check函数,只处理指定的表情,避免无关反应触发逻辑。
内容的提问来源于stack exchange,提问作者Human101929
相关产品推荐
相关产品推荐

