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

Discord.js v14中/setup斜杠命令无法执行的问题排查

Discord.js v14 /setup斜杠命令无响应问题修复

问题描述

使用Discord.js v14开发机器人时,/setup斜杠命令能正常显示3个频道选项,但触发后交互未传递到execute方法。经排查,问题出在InteractionCreate事件处理逻辑中,当前仅处理了按钮和模态框交互,未处理斜杠命令交互。

相关代码

setup.js

const { PermissionFlagsBits, SlashCommandBuilder } = require('discord.js');
const unbanModal = require('../Modals/unbanModal.js');

module.exports = {
    data: new SlashCommandBuilder()
        .setName('setup')
        .setDescription('Setup the bot for your server')
        .addChannelOption(option => 
            option.setName('logchan')
            .setDescription('Channel to log moderation actions')
            .setRequired(false)
        )
        .addChannelOption(option => 
            option.setName('appchan')
            .setDescription('Channel to log applications')
            .setRequired(false)
        )
        .addChannelOption(option => 
            option.setName('modalchan')
            .setDescription('Channel to send the appeal application')
            .setRequired(false)
        )
        .setDefaultMemberPermissions(PermissionFlagsBits.KickMembers),
    async execute(interaction) {
        console.log('executing setup');
        try {
            const logChan = interaction.options.getChannel('logchan');
            const appChan = interaction.options.getChannel('appchan');
            const modChan = interaction.options.getChannel('modalchan');
        
            if (logChan || appChan || modChan) {
                console.log('executing unbanModal');
                await unbanModal.execute(interaction);
            } else {
                console.log('No channel was provided');
                interaction.reply({content: 'You must specify at least one channel.', ephemeral: true});
            }
        
        } catch(err) {
            console.log(err);
            interaction.reply({content: 'An error occurred while trying to get the channels from your request.', ephemeral: true});
        }        
    }
}

main.js

const fs = require('node:fs');
const path = require('node:path');
const { Client, Collection, GatewayIntentBits } = require('discord.js');
const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers, GatewayIntentBits.GuildMessages, GatewayIntentBits.GuildMessageReactions, GatewayIntentBits.MessageContent] });
const { botToken } = require('./Src/Credentials/Config.json');

client.commands = new Collection();
client.modals = new Collection();
client.buttons = new Collection();

console.log('client.buttons:', client.buttons);
  

const modalsDir = path.join(__dirname, 'Src', 'Modals');
const eventsPath = path.join(__dirname, 'Src', 'Events');
const commandsPath = path.join(__dirname, 'Src', 'MessageCommands');
const buttonsDir = path.join(__dirname, 'Src', 'Buttons');
console.log('buttonsDir:', buttonsDir);


const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js'));
const eventFiles = fs.readdirSync(eventsPath).filter(file => file.endsWith('.js'));
const buttonFiles = fs.readdirSync(buttonsDir).filter(file => file.endsWith('.js'));
console.log('buttonFiles:', buttonFiles);
const modalFiles = fs.readdirSync(modalsDir).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);
        console.log(`[INFO] Loaded command ${command.data.name}`);
    } else {
        console.log(`[WARNING] The command at ${filePath} is missing either the 'data' or 'execute' property.`);
    }
}

for (const file of eventFiles) {
    const filePath = path.join(eventsPath, file);
    const event = require(filePath);

    if (event.once) {
        client.once(event.name, (...args) => event.execute(...args));
    } else {
        client.on(event.name, (...args) => event.execute(...args));
    }
}

for (const file of buttonFiles) {
    try {
        const button = require(path.join(buttonsDir, file));
        console.log(`[INFO] Loaded button: ${button.name}`);
        client.buttons.set(button.name, button);
    } catch (error) {
        console.log(`[WARNING] Error loading button at ${path.join(buttonsDir, file)}: ${error}`);
    }
}
console.log('[INFO] CLIENT.buttons:', client.buttons);

for (const file of modalFiles) {
    const modal = require(path.join(modalsDir, file));
    client.modals.set(modal.name, modal);
    console.log(`[INFO] Loaded modal: ${modal.name}`);
}

async function startApp() {
    console.log("Starting...");
    try {
        await client.login(botToken);
        console.log(`Successfully logged in ${client.user.tag}`);
    } catch (error) {
        console.log(`Failed to login | ${error}`);
        process.exit(1);
    }
}

startApp();

module.exports = {
    client
}

interactionCreate.js(原问题代码)

const { Client, Collection, Events, GatewayIntentBits } = require('discord.js');
const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers, GatewayIntentBits.GuildMessages, GatewayIntentBits.GuildMessageReactions, GatewayIntentBits.MessageContent] });

module.exports = {
    name: Events.InteractionCreate,
    async execute(interaction) {
        //if (!interaction.isChatInputCommand()) return;

        if (interaction.isModalSubmit()) {
            const modalName = interaction.customId;
            console.log('modalName:', modalName);
            try {
                console.log('client.modals:', client.modals);
                const modalEvent = client.modals.get(modalName);
                if (!modalEvent) return;


            } catch (error) {
                console.log('Error getting modal:', error);
                console.log('client.modals:', client.modals);
                console.log('modalName:', modalName);
            }
            const modalEvent = client.modals.get(modalName);
        
            if (!modalEvent) return;
    
            try {
                await modalEvent.execute(interaction);
            } catch (error) {
                console.error(`Error executing modal event "${modalName}":`, error);
                interaction.reply({ content: 'An error occurred while executing this command.', ephemeral: true });
            }
        } else if (interaction.isButton()) {
            const buttonName = interaction.customId;
            console.log('buttonName:', buttonName);
            const buttons = client.buttons;
            if (!buttons) {
                console.log('No buttons found');
                return;
            }
            const buttonEvent = buttons.find(btn => btn.name === buttonName);
            if (!buttonEvent) {
                console.log(`Button event ${buttonName} not found`);
                return;
            }

            try {
                await buttonEvent.execute(interaction);
            } catch (error) {
                console.error(`Error executing Button event "${buttonEvent}":`, error);
                interaction.reply({ content: 'An error occurred while executing this command.', ephemeral: true });
            }
        }
    }
};

问题根源

  1. 未处理斜杠命令交互:原interactionCreate.js只处理了模态框和按钮交互,完全缺失斜杠命令(ChatInputCommand)的处理逻辑,导致/setup命令触发后无响应。
  2. 错误创建新Client实例:原interactionCreate.js重新创建了一个Discord客户端,而非使用main.js中已初始化并加载了命令的客户端实例,导致无法访问已加载的/setup命令。

修复方案

修改interactionCreate.js,导入main.js的客户端实例,并添加斜杠命令处理逻辑:

修复后的interactionCreate.js

const { Events } = require('discord.js');
// 导入main.js中已初始化的客户端
const { client } = require('../../main.js');

module.exports = {
    name: Events.InteractionCreate,
    async execute(interaction) {
        // 处理斜杠命令
        if (interaction.isChatInputCommand()) {
            const command = client.commands.get(interaction.commandName);
            if (!command) {
                console.error(`找不到命令:${interaction.commandName}`);
                return;
            }

            try {
                await command.execute(interaction);
            } catch (error) {
                console.error(`执行命令${interaction.commandName}出错:`, error);
                // 确保回复不会因为交互超时失败
                await interaction.reply({ 
                    content: '执行命令时发生错误', 
                    ephemeral: true 
                }).catch(err => console.error(err));
            }
        }
        // 处理模态框提交
        else if (interaction.isModalSubmit()) {
            const modalName = interaction.customId;
            try {
                const modalEvent = client.modals.get(modalName);
                if (!modalEvent) return;
        
                await modalEvent.execute(interaction);
            } catch (error) {
                console.error(`执行模态框${modalName}出错:`, error);
                await interaction.reply({ 
                    content: '执行操作时发生错误', 
                    ephemeral: true 
                }).catch(err => console.error(err));
            }
        }
        // 处理按钮点击
        else if (interaction.isButton()) {
            const buttonName = interaction.customId;
            const buttonEvent = client.buttons.get(buttonName);
            if (!buttonEvent) {
                console.log(`找不到按钮事件:${buttonName}`);
                return;
            }

            try {
                await buttonEvent.execute(interaction);
            } catch (error) {
                console.error(`执行按钮事件${buttonName}出错:`, error);
                await interaction.reply({ 
                    content: '执行操作时发生错误', 
                    ephemeral: true 
                }).catch(err => console.error(err));
            }
        }
    }
};

额外检查项

  1. 确认setup.js位于main.js中commandsPath指向的目录(即Src/MessageCommands),否则需要调整路径或修改commandsPath配置。
  2. 若修改了命令结构,需重新部署斜杠命令到Discord服务器,确保Discord能识别最新的命令配置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 15:37:09