discord.js向被踢用户发消息报50007错误排查方案
报错现象
使用discord.js开发Discord机器人,实现「用户被踢出服务器后机器人自动向其发送私信」功能时,触发如下报错:
DiscordAPIError: Cannot send messages to this user at RequestHandler.execute (C:\Users\Shushan\Desktop\discordbot\node_modules\discord.js\src\rest\RequestHandler.js:154:13) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async RequestHandler.push (C:\Users\Shushan\Desktop\discordbot\node_modules\discord.js\src\rest\RequestHandler.js:39:14) { method: 'post', path: '/channels/988657628710334484/messages', code: 50007, httpStatus: 403 }
对应业务代码为kick.js,原始代码如下:
const Discord = require('discord.js'); const client = new Discord.Client({ intents: [Discord.Intents.FLAGS.GUILDS, Discord.Intents.FLAGS.GUILD_MESSAGES] }); const prefix = 'plz '; const fs = require('fs'); client.commands = new Discord.Collection(); module.exports = { name: 'kick', description: 'This Command Kicks People!', execute(message, args){ const member = message.mentions.users.first(); if(member){ const memberTarget = message.guild.members.cache.get(member.id); const f = String(memberTarget); newStr = f.replace('@', ''); newStrTwo = newStr.replace('<', ''); newStrThree = newStrTwo.replace('>', ''); client.users.fetch(newStrThree).then((user) => { try { user.send("txt"); ; } catch (err){ console.log("err"); } }) memberTarget.kick(); message.channel.send("This User Was Kicked Successfully."); }else{ message.channel.send("This User Couldn't Be Kicked."); } } } client.login('TOKEN');
报错原因
- 执行顺序逻辑错误:
user.send()是异步网络请求,代码没有等待请求完成就直接执行了memberTarget.kick(),多数场景下踢人操作会比私信请求先执行完成。用户被踢出服务器后,和机器人不再有共同服务器关系,默认权限下机器人无法向非共同服务器的用户发送私信,直接触发403 50007错误。 - 异步错误捕获失效:
user.send()返回Promise对象,属于异步操作,普通同步try/catch无法捕获异步抛出的错误,导致发送失败的错误直接穿透到进程层抛出。 - 冗余逻辑易引发异常:通过字符串替换从成员tag中提取用户ID的写法完全多余,discord.js的成员对象本身就带有
id属性可以直接获取用户ID,字符串替换存在匹配失败、取错ID的风险。同时在命令文件中重复初始化Discord Client实例,会导致客户端状态不一致,进一步提升请求异常概率。 - 缺少场景兜底判断:即使用户还在服务器内,也存在用户关闭「允许服务器成员发送私信」开关、用户已拉黑机器人等无法发送私信的场景,代码没有对这类场景做兼容处理。
修复方案
- 调整执行顺序:将
execute方法改为异步函数,等待私信发送流程(无论成功失败)走完后,再执行踢人操作。 - 修正错误捕获逻辑:使用async/await搭配try/catch,或者直接给Promise加
.catch()处理异步发送失败的场景,避免报错中断程序。 - 删除冗余逻辑:去掉字符串替换取ID、命令文件内重复初始化Client的无效代码,直接通过成员对象获取用户实例。
- 增加兜底逻辑:私信发送失败时只打印日志,不中断后续踢人流程。
修正后的kick.js参考代码:
module.exports = { name: 'kick', description: 'This Command Kicks People!', async execute(message, args) { const targetUser = message.mentions.users.first(); if (!targetUser) { return message.channel.send("This User Couldn't Be Kicked."); } const memberTarget = message.guild.members.cache.get(targetUser.id); // 先执行私信发送,捕获所有可能的发送失败场景 try { await targetUser.send("你已被移出当前服务器"); } catch (err) { console.log(`向用户${targetUser.tag}发送私信失败,错误码:${err.code}`); } // 私信流程结束后再执行踢人 await memberTarget.kick(); message.channel.send("This User Was Kicked Successfully."); } }
额外注意:需要在机器人主程序初始化Client时,开启对应权限意图,同时确保机器人在对应服务器拥有踢人权限、机器人隐私设置中允许向共同服务器成员发送私信。
内容的提问来源于stack exchange,提问作者Shushan Arora
相关产品推荐
相关产品推荐

