Discord.js presenceUpdate事件报错:无法读取undefined的remove属性
Discord 支持系统 presenceUpdate 事件报错排查
报错定位
抛出的错误为TypeError: Cannot read properties of undefined (reading 'remove'),触发位置是代码第24行的角色移除逻辑,核心原因是Discord.js API 调用方式错误,同时代码存在多处逻辑偏差,具体问题点如下:
- 事件参数顺序错误:
presenceUpdate事件的标准回调参数为(oldPresence, newPresence),你定义的(client, oldMember, newMember, newPresence)参数顺序和结构完全不匹配,导致后续取到的对象全部错位 - 角色操作接口调用错误:
roles属性属于单个服务器成员(GuildMember)实例,你写的members.roles.add()、guild.members.roles.remove()是在成员集合、服务器成员管理器上找roles属性,这两个对象本身没有roles字段,取值自然为undefined,调用remove方法直接抛错 - 状态检测逻辑错误:你过滤完在线成员后取
status[0]做判断,实际拿到的是成员缓存里的第一个用户,根本不是触发本次状态更新的目标用户;且你调用includes的对象是成员实例本身,不是用户设置的自定义状态文本,永远匹配不到你配置的关键词 - 守卫判断顺序错误:你先访问
oldMember.status做判断,后面才判断oldMember/newMember是否为undefined,只要其中一个值为空,前面取属性的步骤就会提前抛错 - 冗余遍历问题:presenceUpdate事件触发时,传入的newPresence对象已经携带了对应服务器ID,不需要遍历客户端缓存的所有服务器,既浪费性能,还可能出现跨服误加角色的问题
修正后可运行代码
// 注意:事件监听器注册时client通过闭包获取,不要放在事件回调参数中 module.exports = (oldPresence, newPresence) => { // 提前做空值拦截 if (!newPresence?.guild || !newPresence.member) return; const guild = newPresence.guild; const targetMember = newPresence.member; // 读取当前服务器配置 const { soutien_role_id: soutienRoleId, soutien_text: soutienText } = client.db.settings.selectSoutien.get(guild.id); if (!soutienRoleId || !soutienText) return; // 检查角色是否存在 const soutienRole = guild.roles.cache.get(soutienRoleId); if (!soutienRole) return; // 检查bot是否有权限操作该角色 if (guild.members.me.roles.highest.position <= soutienRole.position) return; // 跳过无法操作的成员(例如服务器所有者、角色层级高于bot的成员) if (!targetMember.manageable) return; // 提取用户的自定义状态文本 const customActivity = newPresence.activities.find(act => act.type === 'CUSTOM_STATUS'); const statusText = customActivity?.state?.toLowerCase() || ''; const hasSoutienText = statusText.includes(soutienText.toLowerCase()); // 执行角色增删 if (hasSoutienText) { if (!targetMember.roles.cache.has(soutienRoleId)) { targetMember.roles.add(soutienRole).catch(console.error); } } else { if (targetMember.roles.cache.has(soutienRoleId)) { targetMember.roles.remove(soutienRole).catch(console.error); } } }
前置配置注意事项
- 需要在Discord开发者后台对应Bot的设置页,开启
Presence Intent和Server Members Intent两个特权意图,否则无法接收到完整的presence更新事件,也拿不到完整的成员缓存 - 确保Bot在服务器内的角色位置,高于你要自动分配的
soutien_role_id对应角色,否则会抛出权限不足的错误 - 自定义状态文本存在
activities数组中类型为CUSTOM_STATUS的项里,state字段才是用户输入的状态内容,不要和presence.status字段混淆——后者存的是online/idle/dnd/offline的在线状态枚举值,不可能包含你配置的关键词
内容的提问来源于stack exchange,提问作者InFuzz
相关产品推荐
相关产品推荐

