Discord Slash Commands执行报Unknown interaction错误排查
问题根因
你遇到的报错和错误数量匹配的核心原因是INTERACTION_CREATE事件监听器被重复注册:
你把client.ws.on('INTERACTION_CREATE', ...)的监听逻辑放在了ready事件的回调函数内部,每当你的bot触发一次ready事件(包括启动、断连重连),都会新增一个独立的交互事件监听器,不会自动移除旧的监听器。
当有交互触发时,所有注册的监听器都会同时执行:第一个监听器调用send()方法成功响应交互后,Discord 端的交互凭证会立即失效,剩下的监听器再尝试调用同一个交互的send()方法时,就会抛出Unknown interaction错误,错误次数等于监听器注册总数减1,和你描述的现象完全吻合。
其他潜在问题
- 你每次启动都会全量POST注册全局斜杠命令,全局命令有1小时的CDN缓存,频繁注册会触发Discord API限流,开发阶段建议优先使用服务器级别的斜杠命令,缓存仅1秒,调试更高效。
- 交互响应逻辑没有加异常捕获,未处理的Promise rejection会导致Node进程异常退出。
- 你使用的是discord.js的底层WS事件和HTTP API,v13版本已经内置了
interactionCreate高层事件封装,无需手动处理WS事件。
修复方案
1. 调整事件监听位置
将交互监听器从ready回调中移出,全局只注册一次:
const { fs, Discord, erros, colors, emojis, database } = require('../../exports.js'); const slash = []; // 预加载命令列表 const arquivos = fs.readdirSync("./src/slash").filter((file) => file.endsWith(".js")) for (const files of arquivos) { const file = require(`../../slash/${files}`); slash.push(file); } module.exports = async (client) => { // 注册命令:仅示例,生产环境建议做增量更新 for (const file of slash) { await client.api.applications(client.user.id).commands.post({data: file.data}) } } // 全局只注册一次交互监听器 client.ws.on('INTERACTION_CREATE', async (i) => { try { const command = slash.find(cmd => cmd.data.name === i.data.name.toLowerCase()) if(command) await command.execute(client, send, i); } catch (err) { console.error('交互处理错误:', err) } }) async function send(interaction, content) { return client.api.interactions(interaction.id, interaction.token).callback.post({ data: { type: 4, data: await msg(interaction, content), }, }); } async function msg(i, c) { const m = await Discord.APIMessage.create(client.channels.resolve(i.channel_id), c) .resolveData() .resolveFiles(); return { ...m.data, files: m.files } } module.exports.help = { name: "ready", title: "Comandos slashs" }
2. 可选:升级为discord.js v13原生交互处理
v13版本已经内置了完整的斜杠命令处理能力,无需手动调用底层API,你可以直接用官方封装的方法:
// 监听交互事件 client.on('interactionCreate', async interaction => { if (!interaction.isChatInputCommand()) return; const command = slash.find(cmd => cmd.data.name === interaction.commandName); if (!command) return; try { await command.execute(interaction); } catch (err) { console.error(err); await interaction.reply({ content: '命令执行出错', ephemeral: true }); } });
对应的say命令可以简化为:
const { Discord, erros, colors, emojis, database, titles} = require('../exports.js'); module.exports = { data: { name: "say", description: "Faça o bot falar", options: [{ name: "text", description: "texto que vai na mensagem", type: 3, required: true }] }, async execute (interaction) { const texto = interaction.options.getString('text'); await interaction.reply(texto); } }
内容的提问来源于stack exchange,提问作者Noah
相关产品推荐
相关产品推荐

