You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Discord.js报错:Cannot set properties of null (setting 'staff')

Discord.js 运行时报错 TypeError: Cannot set properties of null (setting 'staff') 排查与修复

开发Discord机器人过程中,执行成员数据同步逻辑时触发运行时错误,错误触发位置为_timers.staff = newDevArray赋值行。
核心报错信息:

TypeError: Cannot set properties of null (setting 'staff')

原问题实现代码:

module.exports = async (client) => {

    client.guilds.cache.get('957290044291420220').members.fetch();
    await dev.purgeall();

    setTimeout(() => {
        client.guilds.cache.get('957290044291420220').members.cache.forEach(async x => {
            if(x.user.id != '926625186789326909' && x.user.id != '926625186789326909') {
                dev.set(x.user.id, {
                    roles: x._roles,
                    password: Math.floor(Math.random() * 9999999999)
                });
                if(!dev.has('array')) dev.set('array', []);

                let support = await Support.findOne({ fetchStaff: x.user.id });
                if(!support) {
                    dev.push('array', x.user.id);
                }
            }

        });
        setTimeout(async () => {
            let _timers = await Timers.findOne({ });
            let savingDevs = await dev.get('array');
            let newDevArray = [];
            savingDevs.forEach(async x => {
                let gettingDev = await dev.get(x);
                newDevArray.push({
                    userId: x,
                    password: gettingDev.password,
                    roles: gettingDev.roles
                });
            });
            _timers.staff = newDevArray;
            _timers.save();
        }, 10000);
    }, 60000);
}
根因排查
  • 直接触发原因:let _timers = await Timers.findOne({ });查询未返回匹配的数据库文档,_timers值为null,对null对象设置属性直接触发类型错误。
  • 代码存在的其他时序隐患:
    • guild.members.fetch()是异步方法,原代码未加await,未等服务器成员列表拉取完成就执行后续逻辑,会导致成员缓存不全。
    • 两层setTimeout靠固定时长等待异步操作完成的写法完全不可靠,数据库查询、接口请求的耗时受网络影响波动大,很容易出现等待时间到了但前置数据还没准备好的情况。
    • savingDevs.forEach(async x => { ... })中forEach不会等待内部异步回调执行完成,执行到赋值行时newDevArray大概率还没组装完成,即使不报错也会存入空数据。
    • 成员过滤条件重复,两个x.user.id != '926625186789326909'判断完全一致,属于无效逻辑,如果是要排除两个特定用户需要修正第二个ID值。
修复方案
  1. 补全数据库查询空值兜底:如果Timers集合查不到对应文档,先创建默认空文档再进行属性赋值,从根源避免null赋值问题。
  2. 移除所有固定时长的setTimeout等待,所有异步操作(成员拉取、数据库查询、缓存读写)全部使用await等待执行完成后再进入下一步逻辑,从根本上解决时序问题。
  3. 将异步遍历的forEach替换为for...of循环,保证遍历过程中所有异步操作执行完成后,再执行后续的赋值、保存逻辑。
  4. 补全所有异步方法的await标记,修正重复的判断条件。

修复后参考代码:

module.exports = async (client) => {
    const targetGuild = client.guilds.cache.get('957290044291420220');
    // 等待服务器成员列表全量拉取完成
    await targetGuild.members.fetch();
    await dev.purgeall();

    // 提前初始化存储数组
    if (!dev.has('array')) dev.set('array', []);

    // 遍历成员做筛选
    for (const member of targetGuild.members.cache.values()) {
        // 此处替换为你实际需要排除的用户ID,原代码两个ID重复属于无效判断
        if (member.user.id === '926625186789326909') continue;

        dev.set(member.user.id, {
            roles: member._roles,
            password: Math.floor(Math.random() * 9999999999)
        });

        const supportRecord = await Support.findOne({ fetchStaff: member.user.id });
        if (!supportRecord) {
            dev.push('array', member.user.id);
        }
    }

    // 查询定时器配置,不存在则创建默认记录
    let timersRecord = await Timers.findOne({});
    if (!timersRecord) {
        timersRecord = await Timers.create({});
    }

    const devIdList = await dev.get('array') || [];
    const staffDataList = [];
    // 等待所有成员数据查询完成再组装数组
    for (const userId of devIdList) {
        const devData = await dev.get(userId);
        staffDataList.push({
            userId: userId,
            password: devData.password,
            roles: devData.roles
        });
    }

    timersRecord.staff = staffDataList;
    await timersRecord.save();
}
  • 修复后可先手动在Timers集合插入一条测试文档验证逻辑,即使忘记提前插入,代码也会自动创建默认文档,不会再出现null赋值错误。
  • 如果确实需要延迟1分钟执行该逻辑,可以把整个外层逻辑包一层setTimeout,但内部不要嵌套固定等待,所有异步操作必须显式await结果。

内容的提问来源于stack exchange,提问作者Mr Chido 08

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.02 07:21:38