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 }); } } } };
问题根源
- 未处理斜杠命令交互:原
interactionCreate.js只处理了模态框和按钮交互,完全缺失斜杠命令(ChatInputCommand)的处理逻辑,导致/setup命令触发后无响应。 - 错误创建新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)); } } } };
额外检查项
- 确认
setup.js位于main.js中commandsPath指向的目录(即Src/MessageCommands),否则需要调整路径或修改commandsPath配置。 - 若修改了命令结构,需重新部署斜杠命令到Discord服务器,确保Discord能识别最新的命令配置。
内容的提问来源于stack exchange,提问作者Eli
相关产品推荐
相关产品推荐

