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

使用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属性时触发报错。这通常是因为:

  1. 命令在DM中被调用,此时交互对象没有member属性;
  2. discord.js v14+版本中,全局命令的交互未正确获取到服务器成员信息;
  3. 机器人缺少GuildMembers相关权限,无法获取成员数据。

修正步骤

  1. 限制命令使用环境:在execute函数开头添加校验,禁止在DM中使用命令:
    if (!interaction.guild) return interaction.editReply("此命令仅能在服务器内使用");
    
  2. 确保获取有效成员对象:替换原有的成员判断逻辑,兼容无法直接获取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("你需要加入一个语音频道才能使用此命令");
    
  3. 更新成员引用:把所有interaction.member.voice.channel替换为member.voice.channel,例如:
    if (!queue.connection) await queue.connect(member.voice.channel);
    
  4. 检查机器人权限:邀请机器人时勾选GuildMembers权限范围,同时在服务器内给机器人分配ViewChannel、Connect、Speak等语音相关权限。
  5. 修正拼写错误:将子命令search的描述里的sogn改为song。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 12:10:19