Discord.js出现DiscordAPIError: Unknown Message错误原因排查问询
错误触发原因
你遇到的DiscordAPIError: Unknown Message(错误码10008,HTTP状态404)核心含义是调用delete方法的目标消息已经在Discord服务器中不存在,无法执行删除操作,具体触发逻辑如下:
- 核心问题是重复绑定
AudioPlayerStatus.Idle事件监听器:你每次发送播放提示消息时,都会通过client.player.on()新增一个Idle事件回调,这些回调不会自动销毁,会一直累积在播放器的事件队列中。 - 当首次播放结束触发Idle事件时,所有累积的历史回调都会同时执行:最早绑定的回调会尝试删除已经被之前操作删掉的历史消息,自然就会抛出找不到消息的错误。
- 你额外注册的全局Idle监听器会调用
next.run()执行切歌逻辑,切歌时又会新增新的Idle监听器,进一步加剧监听器累积的问题。
解决方案
方案1:统一在全局Idle监听器中处理消息删除(更推荐)
不要每次发消息都新增监听器,把当前播放消息存储在client全局属性中,统一在已有的全局Idle监听器中处理删除,同时增加异常捕获避免偶发报错:
首先修改消息发送逻辑:
// 发送播放提示后将消息实例存储到client全局属性 client.nowPlayingMsg = await client.message.channel.send({ content: `Song "${client.currentSong}" is playing`, components: [row], });
然后修改全局Idle监听器逻辑:
client.player.on(AudioPlayerStatus.Idle, async () => { // 先处理历史播放消息删除 if (client.nowPlayingMsg && client.nowPlayingMsg.deletable) { try { await client.nowPlayingMsg.delete(); } catch (err) { // 捕获异常,消息已经被删除等场景直接忽略即可 } client.nowPlayingMsg = null; } // 原有切歌逻辑不变 if (!client.loop) client.playlist.shift(); if (client.playlist.length === 0) return; next.run(client.message, client.args, client); });
方案2:单次事件绑定+异常捕获
如果你要保留在消息发送处绑定回调的写法,将on改为once(单次事件监听,触发后自动销毁,不会累积),同时增加错误捕获:
await client.message.channel.send({ content: `Song "${client.currentSong}" is playing`, components: [row], }) .then(message => { // 用once替代on,只监听一次Idle事件,执行后自动销毁 client.player.once(AudioPlayerStatus.Idle, async () => { try { if (message.deletable) await message.delete(); } catch (e) { // 忽略删除失败场景 } }); });
额外注意项
- 确认机器人拥有目标频道的管理消息权限,否则会出现权限不足导致的删除失败
- 若消息发送超过14天,Discord官方限制机器人无法删除此类消息,也会触发删除报错,可根据业务逻辑增加发送时间判断规避
内容的提问来源于stack exchange,提问作者Suspense
相关产品推荐
相关产品推荐

