Discord.js机器人执行命令后触发DiscordAPIError[40060]求助
问题分析
报错DiscordAPIError[40060]: Interaction has already been acknowledged的核心原因是同一个交互被多个监听器重复处理:
- 代码里存在两个
InteractionCreate事件监听器,第一个监听器处理ping命令时调用interaction.reply()确认了交互; - 第二个监听器会再次捕获同一个
ping交互,尝试执行命令或报错回复,此时交互已被确认,触发Discord API的重复确认限制。
解决方案
合并两个InteractionCreate监听器,确保每个交互只被处理一次,同时调整逻辑避免重复确认:
修改后的完整代码
const fs = require('node:fs'); const path = require('node:path') const { Client, Events, GatewayIntentBits, Collection, ActionRowBuilder, EmbedBuilder, StringSelectMenuBuilder } = require('discord.js'); const { token } = require('./config.json'); const client = new Client({ intents: [GatewayIntentBits.Guilds] }); client.commands = new Collection(); const commandsPath = path.join(__dirname,'commands'); const commandFiles = fs.readdirSync(commandsPath).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); }else{ console.log(`[WARNING] The command at ${filePath} is missing`); } } client.once(Events.ClientReady, () => { console.log('Ready!'); }) // 合并后的单一InteractionCreate监听器 client.on(Events.InteractionCreate, async interaction => { // 处理聊天输入命令 if (interaction.isChatInputCommand()) { // 单独处理ping命令(若不想移到commands文件夹) if (interaction.commandName === 'ping') { const row = new ActionRowBuilder() .addComponents( new StringSelectMenuBuilder() .setCustomId('select') .setPlaceholder('Nothing selected') ); const embed = new EmbedBuilder() .setColor(0x0099FF) .setTitle('pong') .setDescription('Some description here') .setImage('https://media.istockphoto.com/id/1310339617/vector/ping-pong-balls-isolated-vector-illustration.jpg?s=612x612&w=0&k=20&c=sHlz5sbJrymDo7vfTQIuaj4lbmwlvAhVE7Uk_631ZA8=') await interaction.reply({ content: 'Pong!', ephemeral: true, embeds: [embed]}); // 终止后续逻辑,避免重复处理 return; } // 处理commands文件夹中的其他命令 const command = interaction.client.commands.get(interaction.commandName); if (!command) { console.error(`No command matching ${interaction.commandName} was found`) return; } try { await command.execute(interaction); } catch(error) { console.error(error); // 检查交互状态,避免重复回复 if (interaction.replied || interaction.deferred) { await interaction.followUp({content: '执行命令时发生错误!', ephemeral: true}); } else { await interaction.reply({content: '执行命令时发生错误!', ephemeral: true}); } } } // 可在此扩展处理其他交互类型,比如按钮、选择菜单等 // if (interaction.isStringSelectMenu()) { // // 选择菜单处理逻辑 // } }); client.login(token);
关键改动说明
- 合并监听器:将两个独立的
InteractionCreate监听器合并为一个,避免同一个交互被多次捕获。 - 终止逻辑:处理完
ping命令后添加return,确保后续的命令处理代码不会重复执行。 - 错误处理优化:报错回复前检查
interaction.replied或interaction.deferred状态,若交互已确认则改用followUp()回复,避免触发重复确认报错。
可选模块化优化
如果遵循Discord.js的命令模块化规范,可将ping命令逻辑移到commands/ping.js文件中,让代码更整洁:
commands/ping.js示例
const { SlashCommandBuilder, ActionRowBuilder, EmbedBuilder, StringSelectMenuBuilder } = require('discord.js'); module.exports = { data: new SlashCommandBuilder() .setName('ping') .setDescription('回复Pong!'), async execute(interaction) { const row = new ActionRowBuilder() .addComponents( new StringSelectMenuBuilder() .setCustomId('select') .setPlaceholder('未选择任何内容') ); const embed = new EmbedBuilder() .setColor(0x0099FF) .setTitle('pong') .setDescription('一些描述内容') .setImage('https://media.istockphoto.com/id/1310339617/vector/ping-pong-balls-isolated-vector-illustration.jpg?s=612x612&w=0&k=20&c=sHlz5sbJrymDo7vfTQIuaj4lbmwlvAhVE7Uk_631ZA8='); await interaction.reply({ content: 'Pong!', ephemeral: true, embeds: [embed]}); }, };
此时主文件的InteractionCreate监听器可简化为:
client.on(Events.InteractionCreate, async interaction => { if (!interaction.isChatInputCommand()) return; const command = interaction.client.commands.get(interaction.commandName); if (!command) { console.error(`未找到匹配${interaction.commandName}的命令`) return; } try { await command.execute(interaction); } catch(error) { console.error(error); if (interaction.replied || interaction.deferred) { await interaction.followUp({content: '执行命令时发生错误!', ephemeral: true}); } else { await interaction.reply({content: '执行命令时发生错误!', ephemeral: true}); } } });
内容的提问来源于stack exchange,提问作者Tarun Kumar
相关产品推荐
相关产品推荐

