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
相关产品推荐
相关产品推荐

