Discord机器人/play命令报错:AttributeError 'str'对象无author属性
错误信息
2023-12-01 21:25:11 ERROR discord.ext.commands.bot Ignoring exception in command pusti
Traceback (most recent call last):
File "C:\Users\x\AppData\Roaming\Python\Python312\site-packages\discord\ext\commands\core.py", line 235, in wrapped
ret = await coro(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\discord-bot\main.py", line 149, in pusti
voice_channel = ctx.author.voice.channel
^^^^^^^^^^
AttributeError: 'str' object has no attribute 'author'The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "C:\Users\x\AppData\Roaming\Python\Python312\site-packages\discord\ext\commands\bot.py", line 1350, in invoke
await ctx.command.invoke(ctx)
File "C:\Users\x\AppData\Roaming\Python\Python312\site-packages\discord\ext\commands\core.py", line 1029, in invoke
await injected(*ctx.args, **ctx.kwargs) # type: ignore
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\x\AppData\Roaming\Python\Python312\site-packages\discord\ext\commands\core.py", line 244, in wrapped
raise CommandInvokeError(exc) from exc
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: 'str' object has no attribute 'author'
问题代码
@client.command(name = "pusti", aliases = ["p", "play", "playing"], help = "播放你提供链接的歌曲。🎵") async def pusti(self, ctx, *args): query = " ".join(args) voice_channel = ctx.author.voice.channel if voice_channel is None: await ctx.send("➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖\n请先加入语音频道!🎵\n➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖") elif self.is_paused: self.vc.resume() else: song = self.search_yt(query) if type(song) == type(True): await ctx.send("➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖\n你的歌曲已加入等待队列。🎵\n➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖") self.music_queue.append([song, voice_channel]) if self.is_playing == False: await self.play_music(ctx)
错误原因
- 参数定义错误:代码中命令函数用了
self作为第一个参数,但该函数并非commands.Cog类的成员方法,导致参数顺序混乱。实际调用时,Discord传入的上下文对象ctx被赋值给self,歌曲查询字符串被赋值给ctx,最终引发'str' object has no attribute 'author'错误。 - 命令类型不匹配:你使用的是Discord斜杠命令(
/pusti),但代码中用的@client.command装饰器仅支持前缀式命令(比如!pusti),不兼容斜杠命令。
修正方案
方案1:保留前缀式命令(比如!pusti)
去掉多余的self参数,调整相关属性调用:
@client.command(name = "pusti", aliases = ["p", "play", "playing"], help = "播放你提供链接的歌曲。🎵") async def pusti(ctx, *args): query = " ".join(args) # 先判断用户是否在语音频道 if not ctx.author.voice: await ctx.send("➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖\n请先加入语音频道!🎵\n➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖") return voice_channel = ctx.author.voice.channel if client.is_paused: client.vc.resume() else: song = search_yt(query) # 若search_yt是全局函数,去掉self. if isinstance(song, bool): # 替代type(song) == type(True)的更规范写法 await ctx.send("➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖\n你的歌曲已加入等待队列。🎵\n➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖") client.music_queue.append([song, voice_channel]) if client.is_playing == False: await play_music(ctx) # 若play_music是全局函数,去掉self.
方案2:适配斜杠命令(/pusti)
使用Discord应用命令装饰器@client.tree.command,调整参数和上下文对象:
import discord @client.tree.command(name="pusti", description="播放你提供链接的歌曲。🎵") async def pusti(interaction: discord.Interaction, query: str): # 判断用户是否在语音频道 if not interaction.user.voice: await interaction.response.send_message("➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖\n请先加入语音频道!🎵\n➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖") return voice_channel = interaction.user.voice.channel if client.is_paused: client.vc.resume() else: song = search_yt(query) if isinstance(song, bool): await interaction.response.send_message("➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖\n你的歌曲已加入等待队列。🎵\n➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖") client.music_queue.append([song, voice_channel]) if client.is_playing == False: await play_music(interaction) # 注意play_music需适配Interaction对象 # 启动机器人时同步斜杠命令到Discord @client.event async def on_ready(): await client.tree.sync() print(f"Logged in as {client.user}")
注意事项
- 如果
search_yt、play_music以及is_paused、music_queue等是类成员,需确保命令函数属于对应的commands.Cog类,此时self参数才合法,且装饰器应使用@commands.command而非@client.command。 - 斜杠命令需在机器人启动时调用
await client.tree.sync()完成同步,否则Discord端不会显示该命令。
内容的提问来源于stack exchange,提问作者exibo

