Discord.js V14机器人移动频道成员报错问题排查
解决Discord.js v14移动语音频道成员的TypeError问题
问题描述
从Discord.js v12升级到v14.7.1(Node.js版本18.12.1)后,实现频道成员移动功能的代码出现报错:
TypeError: Cannot read properties of undefined (reading 'setChannel') TypeError: Cannot read properties of undefined (reading 'channelId')
原v12代码可正常运行,v14版本的代码执行时触发上述错误。
相关代码
main.js
const { Client, Events, GatewayIntentBits, Collection, ActivityType } = require("discord.js"); const fs = require("node:fs"); const path = require("node:path"); const { token } = require("./config.json"); const botIntents = [ GatewayIntentBits.Guilds, GatewayIntentBits.DirectMessages, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent, GatewayIntentBits.GuildMembers, GatewayIntentBits.GuildPresences, GatewayIntentBits.GuildVoiceStates ]; const client = new Client({ intents: botIntents, partials: ["CHANNEL"] }); client.commands = new Collection(); const commandsPath = path.join(__dirname, "commands"); const commandFiles = fs.readdirSync(commandsPath).filter((file) => file.endsWith(".js")); for (const file of commandFiles) { const filePath = path.join(commandsPath, file); const command = require(filePath); if ("data" in command && "execute" in command) { client.commands.set(command.data.name, command); } else { console.log(`[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.`); } } // Bot ready event client.once(Events.ClientReady, (c) => { console.log(`Logged in as ${c.user.tag}`); c.user.setActivity("/help", { type: ActivityType.Watching }); }); // Message input to command client.on(Events.InteractionCreate, async (interaction) => { if (!(interaction.isChatInputCommand())) return; const command = interaction.client.commands.get(interaction.commandName); if (!(command)) { console.error(`No command matching ${interaction.commandName} was found.`); return; } try { await command.execute(interaction); } catch (error) { console.error(error); await interaction.reply({ content: "There was an error while executing this command!", ephemeral: true }); } }); client.login(token);
v12可用代码
module.exports = { name: "my_name", description: "my_description", execute(message, args) { const member = message.mentions.members.first(); if (!(args[1])) { const embed = new Discord.MessageEmbed() .setTitle("my_command") .setColor(0x992d22) .setDescription("my_description") .setFooter(`Requested by ${message.author.tag}.`, message.author.displayAvatarURL); message.channel.send(embed); } if (!member) return message.reply("enter a member name.") if (!member.voice.channel) return message.reply("the member is not in a voice channel."); if (!message.member.voice.channel) return message.reply("you need to join a voice channel first."); message.channel.send("my_message"); member.voice.setChannel("my_channel_id"); } }
v14尝试代码
module.exports = { data: new SlashCommandBuilder() .setName("my_name") .setDescription("my_description") .addUserOption((option) => option .setName("member") .setDescription("my_description") .setRequired(true) ) .setDMPermission(false), async execute(interaction) { const master = interaction.user.username; const target = interaction.options.getUser("member"); const cageId = "my_channel_id"; if (!(interaction.member.voice.channel)) { return await interaction.reply({ content: "You need to join a Voice-Channel first.", ephemeral: true }); } if (!(target.voice.channelId)) { return await interaction.reply({ content: "The Member is currently not in a Voice-Channel.", ephemeral: true }); } await target.voice.setChannel(cageId); const embed = new EmbedBuilder() .setColor(0x992d22) .setTitle("my_title") .setDescription("my_description") .setFooter({ text: `Requested by ${master}` }) .setTimestamp(); return await interaction.reply({ embeds: [embed] }); }, }
报错信息
TypeError: Cannot read properties of undefined (reading 'setChannel') TypeError: Cannot read properties of undefined (reading 'channelId')
问题原因与修复方案
核心问题是:Discord.js v14中,getUser()返回的是全局User对象,而语音状态(voice属性)仅存在于服务器专属的GuildMember对象中。你用getUser()拿到的目标对象没有voice属性,自然会触发undefined报错。
修复步骤
- 替换对象获取方式:将
interaction.options.getUser("member")改为interaction.options.getMember("member"),获取目标用户的GuildMember实例。 - 补全必要导入:v14命令中需要导入
SlashCommandBuilder和EmbedBuilder,否则会报未定义错误。 - 调整异常处理:添加
try/catch捕获移动成员时的权限或其他异常。
修复后的v14命令代码
const { SlashCommandBuilder, EmbedBuilder } = require('discord.js'); module.exports = { data: new SlashCommandBuilder() .setName("my_name") .setDescription("my_description") .addUserOption((option) => option .setName("member") .setDescription("my_description") .setRequired(true) ) .setDMPermission(false), async execute(interaction) { const master = interaction.user.username; // 获取GuildMember对象而非User对象 const target = interaction.options.getMember("member"); const cageId = "my_channel_id"; if (!interaction.member.voice.channel) { return await interaction.reply({ content: "你需要先加入一个语音频道。", ephemeral: true }); } // 先判断target.voice是否存在,再检查channelId if (!target.voice || !target.voice.channelId) { return await interaction.reply({ content: "该成员当前不在语音频道中。", ephemeral: true }); } try { // 移动成员到目标频道 await target.voice.setChannel(cageId); } catch (err) { console.error(err); return await interaction.reply({ content: "移动成员失败,请检查机器人是否拥有「移动成员」权限。", ephemeral: true }); } const embed = new EmbedBuilder() .setColor(0x992d22) .setTitle("my_title") .setDescription("my_description") .setFooter({ text: `Requested by ${master}` }) .setTimestamp(); return await interaction.reply({ embeds: [embed] }); }, }
额外注意事项
- 确保机器人在目标服务器中拥有移动成员的权限(服务器设置→角色→机器人角色→开启「移动成员」权限)。
- 你的main.js已经正确启用了
GuildVoiceStates意图,无需修改,这是获取语音状态的必要条件。
内容的提问来源于stack exchange,提问作者Vincent
相关产品推荐
相关产品推荐

