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

Discord JS报错:无法读取undefined的setChannel属性及多提及用户问题

解决Discord.js多用户语音频道转移的setChannel未定义错误

首先咱们得搞清楚你遇到的错误根源:你用getUserFromMention获取的是User对象,但voice属性只存在于GuildMember对象中。

User代表Discord平台上的全局用户,而GuildMember是用户在某个具体服务器(Guild)里的实例——只有后者才包含用户在该服务器的语音状态、角色等信息。你之前用message.mentions.members.first()能正常工作,就是因为它返回的是GuildMember,而你新写的getUserFromMention返回的是User,自然找不到voice属性,也就抛出了Cannot read property 'setChannel' of undefined的错误。

下面给你几个可行的修复方案,从简单到灵活:

方案一:直接利用Discord.js内置的提及解析(最推荐)

其实完全不用自己写getUserFromMention函数,Discord.js已经帮你处理了所有提及的成员,直接用message.mentions.members就能拿到所有被提及的GuildMember集合,支持任意数量的用户提及,代码更简洁:

// 解析目标语音频道,同时校验类型
const targetChannel = client.channels.cache.find(channel => 
  channel.name === args[0] && channel.type === 'GUILD_VOICE'
);
if (!targetChannel) {
  return message.reply('请指定一个有效的语音频道!');
}

// 处理发送命令的用户(你自己)
try {
  await message.member.voice.setChannel(targetChannel);
} catch (err) {
  message.reply('你当前不在语音频道里,无法转移!');
}

// 批量处理所有被提及的用户
message.mentions.members.forEach(async member => {
  try {
    await member.voice.setChannel(targetChannel);
    message.channel.send(`已将 ${member.displayName} 转移至 ${targetChannel.name}`);
  } catch (err) {
    message.channel.send(`无法转移 ${member.displayName}:该用户不在语音频道或机器人无操作权限`);
  }
});

方案二:修改getUserFromMention函数返回GuildMember

如果你坚持要用自己的提及解析函数,只需要把它改成从当前服务器的成员缓存中获取,而不是全局用户缓存:

// 修改后的函数,返回当前服务器的GuildMember
function getMemberFromMention(mention, guild) {
  if (!mention) return;
  if (mention.startsWith('<@') && mention.endsWith('>')) {
    mention = mention.slice(2, -1);
    if (mention.startsWith('!')) {
      mention = mention.slice(1);
    }
    // 从当前服务器成员缓存中获取实例
    return guild.members.cache.get(mention);
  }
}

// 调用时传入当前服务器(message.guild)
const targetChannel = client.channels.cache.find(channel => channel.name === args[0]);
const member1 = getMemberFromMention(args[1], message.guild);
const member2 = getMemberFromMention(args[2], message.guild);

// 先做基础校验
if (!targetChannel || targetChannel.type !== 'GUILD_VOICE') {
  return message.reply('无效的语音频道!');
}

// 处理自身
if (message.member.voice.channel) {
  message.member.voice.setChannel(targetChannel);
} else {
  message.reply('你不在语音频道里!');
}

// 处理第一个提及用户
if (member1 && member1.voice.channel) {
  member1.voice.setChannel(targetChannel);
} else {
  message.reply('第一个用户不存在或不在语音频道!');
}

// 处理第二个提及用户
if (member2 && member2.voice.channel) {
  member2.voice.setChannel(targetChannel);
} else {
  message.reply('第二个用户不存在或不在语音频道!');
}

方案三:从User转换为GuildMember

如果你不想修改原有的getUserFromMention函数,也可以把获取到的User转换成当前服务器的GuildMember:

const user1 = getUserFromMention(args[1]);
// 将User转换为当前服务器的GuildMember
const member1 = user1 ? message.guild.members.cache.get(user1.id) : null;

// 调用前先检查实例是否存在
if (member1 && member1.voice.channel) {
  member1.voice.setChannel(targetChannel.id);
} else {
  message.reply('用户1无效或不在语音频道!');
}

额外提示

不管用哪种方案,都建议加上错误处理:

  • 检查目标频道是否存在且为语音频道
  • 检查用户是否处于语音频道中
  • 捕获setChannel可能抛出的权限错误(比如机器人没有移动用户的权限)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:10:29