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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 18:17:07