Discord.js(v14)封禁命令验证用户最高角色时触发TypeError错误
问题:Discord.js v14 封禁命令角色层级验证触发TypeError
错误信息
TypeError: Cannot read properties of undefined (reading 'position') at Object.execute (D:\Matteo\Bot Discord\AnotherBot\Commands\Moderation\ban.js:63:34) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async Object.execute (D:\Matteo\Bot Discord\AnotherBot\Events\interactionCreate.js:16:13)
对应封禁命令代码
const { SlashCommandBuilder, PermissionFlagsBits, EmbedBuilder } = require('discord.js'); const fs = require('fs'); const yaml = require('js-yaml'); const cmdconfig = yaml.load(fs.readFileSync('./commands.yml')); const serverLanguage = require('../../Schemas/serverLanguage'); module.exports = { data: new SlashCommandBuilder() .setName(cmdconfig.ban) .setDescription(cmdconfig.banDesc) .addUserOption(option => option.setName(cmdconfig.banUserOption) .setDescription(cmdconfig.banUserOptionDesc) .setRequired(true) ) .addStringOption(option => option.setName(cmdconfig.banReasonOption) .setDescription(cmdconfig.banReasonOptionDesc) .setRequired(false) ) .addStringOption(option => option.setName(cmdconfig.banDMOption) .setDescription(cmdconfig.banDMOptionDesc) .setRequired(false) .addChoices( { name: 'True', value: 'true' }, { name: 'False', value: 'false' } ) ), async execute(interaction, client){ const { options, guild } = interaction; const languageDataDB = await serverLanguage.findOne({ Guild: guild.id }) let language; if(!languageDataDB){ language = 'english' } else { language = languageDataDB.Language } const languageStrings = require(`../../Languages/Strings/${language}.json`); const languageEmbeds = require(`../../Languages/Embeds/${language}.json`); const permissionsNamesLanguages = require(`../../Languages/PermissionsNames/${language}.json`); if(!interaction.member.permissions.has(PermissionFlagsBits.BanMembers)) return interaction.reply(`${languageStrings.noPermissionsForCommand} \`${permissionsNamesLanguages.BanMembers}\``) const user = options.getUser(cmdconfig.banUserOption); const reason = options.getString(cmdconfig.banReasonOption) || languageStrings.NoReasonGiven; const DMuser = options.getString(cmdconfig.banDMOption) || false; const userToBan = guild.members.cache.get(user.id) if(userToBan == client.user.id) return interaction.reply(languageStrings.banUserIsTheBotCommand) if(userToBan == interaction.user.id) return interaction.reply(languageStrings.banUserIsExecutorCommand) if(!userToBan) return interaction.reply(languageStrings.banUserNotFoundCommand) if(!userToBan?.bannable) return interaction.reply(languageStrings.banUserNotBannableCommand) if(userToBan.id == guild.ownerId) return interaction.reply(languageStrings.banUserIsTheGuildOwnerCommand) const executorRolePosition = interaction.member.roles.highest.position; const userToBanRolePosition = userToBan.roles.highest.position; if(userToBanRolePosition >= executorRolePosition) return interaction.reply(languageStrings.banNoEnoughRolesCommand) const embed = new EmbedBuilder() .setColor('Green') .setDescription(languageEmbeds.banDescriptionCommand1) .setThumbnail(userToBan.displayAvatarURL()) .addFields( { name: languageEmbeds.banUserFieldCommand, value: `${userToBan}` }, { name: languageEmbeds.banReasonFieldCommand, value: `${reason}` } ) const DmEmbed = new EmbedBuilder() .setColor('Red') .setDescription(`${languageEmbeds.banDescriptionCommand2} **${guild.name}**`) .setThumbnail(guild.iconURL()) .addFields( { name: languageEmbeds.banReasonFieldCommand, value: reason } ) let dmUserNotSucceed; if(DMuser == 'true'){ try{ const dmChannel = await userToBan.createDM(); await dmChannel.send({ embeds: [DmEmbed] }) } catch(error) { console.log(error) dmUserNotSucceed = true } } await userToBan.ban({ reason: `Banned by ${interaction.user.username}: ${reason}`}); await interaction.reply({ embeds: [embed] }); if(DMuser == 'true' && dmUserNotSucceed == true) interaction.followUp(languageStrings.banDmError); } }
解决方案
1. 修复成员获取逻辑
缓存获取guild.members.cache.get(user.id)可能因成员不在缓存中返回undefined,导致后续判断失效。改用fetch强制获取成员:
// 替换原userToBan赋值行 const userToBan = await guild.members.fetch(user.id).catch(() => null);
2. 修复对象与字符串的错误比较
原代码中直接用GuildMember对象和用户ID字符串比较,永远返回false,导致前置拦截失效:
// 替换原判断行 if(userToBan.id === client.user.id) return interaction.reply(languageStrings.banUserIsTheBotCommand); if(userToBan.id === interaction.user.id) return interaction.reply(languageStrings.banUserIsExecutorCommand);
3. 添加可选链保护角色层级读取
为避免极端情况导致的undefined报错,给roles.highest添加可选链和默认值:
// 替换原角色层级赋值行 const executorRolePosition = interaction.member.roles.highest?.position ?? 0; const userToBanRolePosition = userToBan.roles.highest?.position ?? 0;
完整修复后的核心代码片段
const user = options.getUser(cmdconfig.banUserOption); const reason = options.getString(cmdconfig.banReasonOption) || languageStrings.NoReasonGiven; const DMuser = options.getString(cmdconfig.banDMOption) || false; // 修复:强制获取成员 const userToBan = await guild.members.fetch(user.id).catch(() => null); // 修复:对象ID比较 if(userToBan.id === client.user.id) return interaction.reply(languageStrings.banUserIsTheBotCommand); if(userToBan.id === interaction.user.id) return interaction.reply(languageStrings.banUserIsExecutorCommand); if(!userToBan) return interaction.reply(languageStrings.banUserNotFoundCommand); if(!userToBan.bannable) return interaction.reply(languageStrings.banUserNotBannableCommand); if(userToBan.id === guild.ownerId) return interaction.reply(languageStrings.banUserIsTheGuildOwnerCommand); // 修复:添加可选链和默认值 const executorRolePosition = interaction.member.roles.highest?.position ?? 0; const userToBanRolePosition = userToBan.roles.highest?.position ?? 0; if(userToBanRolePosition >= executorRolePosition) return interaction.reply(languageStrings.banNoEnoughRolesCommand);
内容的提问来源于stack exchange,提问作者thats_me
相关产品推荐
相关产品推荐

