使用discord.js开发Discord机器人时遇TypeError问题求助
问题:Discord.js机器人play命令触发TypeError: Cannot read properties of undefined (reading 'voice')
我正在用discord.js开发Discord机器人,懂一点Python但刚接触Java。机器人的slash命令里三个能正常运行,但执行play命令时触发错误:TypeError: Cannot read properties of undefined (reading 'voice'),错误位于play.js第30行,机器人不会崩溃。
终端错误栈
TypeError: Cannot read properties of undefined (reading 'voice') at Object.execute (C:\Users\Uporabnik\Desktop\DiscBot\src\commands\Community\play.js:30:27) at Object.execute (C:\Users\Uporabnik\Desktop\DiscBot\src\events\interactionCreate.js:13:27) at Client.<anonymous> (C:\Users\Uporabnik\Desktop\DiscBot\src\functions\handelEvents.js:8:58) at Client.emit (node:events:513:28) at InteractionCreateAction.handle (C:\Users\Uporabnik\Desktop\DiscBot\node_modules\discord.js\src\client\actions\InteractionCreate.js:97:12) at module.exports [as INTERACTION_CREATE] (C:\Users\Uporabnik\Desktop\DiscBot\node_modules\discord.js\src\client\websocket\handlers\INTERACTION_CREATE.js:4:36) at WebSocketManager.handlePacket (C:\Users\Uporabnik\Desktop\DiscBot\node_modules\discord.js\src\client\websocket\WebSocketManager.js:352:31) at WebSocketShard.onPacket (C:\Users\Uporabnik\Desktop\DiscBot\node_modules\discord.js\src\client\websocket\WebSocketShard.js:489:22) at WebSocketShard.onMessage (C:\Users\Uporabnik\Desktop\DiscBot\node_modules\discord.js\src\client\websocket\WebSocketShard.js:328:10) at callListener (C:\Users\Uporabnik\Desktop\DiscBot\node_modules\ws\lib\event-target.js:290:14)
play命令代码
const { SlashCommandBuilder } = require('@discordjs/builders'); const { MessageEmbed } = require('discord.js'); const { QueryType } = require("discord-player") module.exports = { data: new SlashCommandBuilder() .setName("play") .setDescription("Plays songs from youtube") .addSubcommand((subcommand) => subcommand .setName("song") .setDescription("plays a single song from a url") .addStringOption((option) => option.setName("url").setDescription("Paste the song's url").setRequired(true)) ) .addSubcommand((subcommand) => subcommand .setName("playlist") .setDescription("Loads a playlist of songs from a url") .addStringOption((option) => option.setName("url").setDescription("Paste the playlist's url").setRequired(true)) ) .addSubcommand((subcommand) => subcommand .setName("search") .setDescription("Searches for sogn based on provided keywords") .addStringOption((option) => option.setName("searchterms").setDescription("Type in the search keywords").setRequired(true) ) ), async execute( client, interaction ) { if (!interaction.member.voice.channel) return interaction.editReply("You need to be in a voice channel to use this command") const queue = await client.player.createQueue(interaction.guild) if (!queue.connection) await queue.connect(interaction.member.voice.channel) let embed = new MessageEmbed() if (interaction.options.getSubcommand() === "song") { let url = interaction.options.getString("url") const result = await client.player.search(url, { requestedBy: interaction.user, searchEngine: QueryType.YOUTUBE_VIDEO }) if (result.tracks.length === 0) return interaction.editReply("No results") const song = result.tracks[0] await queue.addTrack(song) embed .setDescription(`**[${song.title}](${song.url})** has been added to the Queue`) .setThumbnail(song.thumbnail) .setFooter({ text: `Duration: ${song.duration}`}) } else if (interaction.options.getSubcommand() === "playlist") { let url = interaction.options.getString("url") const result = await client.player.search(url, { requestedBy: interaction.user, searchEngine: QueryType.YOUTUBE_PLAYLIST }) if (result.tracks.length === 0) return interaction.editReply("No results") const playlist = result.playlist await queue.addTracks(result.tracks) embed .setDescription(`**${result.tracks.length} songs from [${playlist.title}](${playlist.url})** have been added to the Queue`) .setThumbnail(playlist.thumbnail) } else if (interaction.options.getSubcommand() === "search") { let url = interaction.options.getString("searchterms") const result = await client.player.search(url, { requestedBy: interaction.user, searchEngine: QueryType.AUTO }) if (result.tracks.length === 0) return interaction.editReply("No results") const song = result.tracks[0] await queue.addTrack(song) embed .setDescription(`**[${song.title}](${song.url})** has been added to the Queue`) .setThumbnail(song.thumbnail) .setFooter({ text: `Duration: ${song.duration}`}) } if (!queue.playing) await queue.play() await interaction.editReply({ embeds: [embed] }) }, }
注:该代码并非完全由我编写,我做了一些修改。
解决方法
错误原因
第30行的interaction.member为undefined,导致读取voice属性时触发报错。这通常是因为:
- 命令在DM中被调用,此时交互对象没有
member属性; - discord.js v14+版本中,全局命令的交互未正确获取到服务器成员信息;
- 机器人缺少
GuildMembers相关权限,无法获取成员数据。
修正步骤
- 限制命令使用环境:在execute函数开头添加校验,禁止在DM中使用命令:
if (!interaction.guild) return interaction.editReply("此命令仅能在服务器内使用"); - 确保获取有效成员对象:替换原有的成员判断逻辑,兼容无法直接获取
interaction.member的场景:// 替换原有的if (!interaction.member.voice.channel)这一行 const member = interaction.member || await interaction.guild.members.fetch(interaction.user.id); if (!member.voice.channel) return interaction.editReply("你需要加入一个语音频道才能使用此命令"); - 更新成员引用:把所有
interaction.member.voice.channel替换为member.voice.channel,例如:if (!queue.connection) await queue.connect(member.voice.channel); - 检查机器人权限:邀请机器人时勾选
GuildMembers权限范围,同时在服务器内给机器人分配ViewChannel、Connect、Speak等语音相关权限。 - 修正拼写错误:将子命令
search的描述里的sogn改为song。
内容的提问来源于stack exchange,提问作者user15090233
相关产品推荐
相关产品推荐

