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

Discord.js v14等级系统迁移报错:无法读取guild属性

Discord.js v14 等级系统迁移报错问题

问题描述

正在将Discord Bot升级为使用Slash Commands,迁移原有等级系统后代码无法正常运行,出现如下报错:

报错信息

D:\Development Projects\04 - Archived Bot Projects\SystemdBot-Beta\src\functions\database\level.js:6
  const guildEnable = getEnable(message.guild.id);
                                        ^

TypeError: Cannot read properties of undefined (reading 'guild')
    at module.exports (D:\Development Projects\04 - Archived Bot Projects\SystemdBot-Beta\src\functions\database\level.js:6:41)
    at Object.<anonymous> (D:\Development Projects\04 - Archived Bot Projects\SystemdBot-Beta\src\bot.js:18:46)
    at Module._compile (node:internal/modules/cjs/loader:1275:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1329:10)
    at Module.load (node:internal/modules/cjs/loader:1133:32)
    at Module._load (node:internal/modules/cjs/loader:972:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:83:12)
    at node:internal/main/run_main_module:23:47

Node.js v19.9.0

相关代码

const config = require('../../../config/config');
const db = require('./cfgdb');
const lvldb = require('./lvldb');

module.exports = async (client, message) => {
  const guildEnable = getEnable(message.guild.id);
  if (guildEnable.leveling !== 1) return;
  const guildSettings = getGuildSettings(message.guild.id);
  if (!guildSettings) return;

  if (message.author.bot) return;

  const userId = message.author.id;
  const guildId = message.guild.id;
  const user = await client.users.fetch(userId);
  const username = user.username;

  const member = message.member;
  const booster = guildSettings.boosterrole;

  let xp;

  if(member.roles.cache.has(booster)) {
    xp = Math.floor(Math.random() * (50 - 35 + 1) + 35);
  } else {
    xp = Math.floor(Math.random() * (20 - 15 + 1) + 15);
  }

  const row = lvldb.prepare('SELECT * FROM level WHERE userid = ? AND guildid = ?').get(userId, guildId);

  if (!row || !('level' in row)) {
    lvldb.prepare('INSERT INTO level (userid, guildid, username, xp, totalxp) VALUES (?, ?, ?, ?, ?)').run(userId, guildId, username, xp, xp);
  } else {
    lvldb.prepare('UPDATE level SET xp = ?, totalxp = ? WHERE userid = ? AND guildid = ?').run(row.xp + xp, row.totalxp + xp, userId, guildId);
  }

  const updatedRow = lvldb.prepare('SELECT * FROM level WHERE userid = ? AND guildid = ?').get(userId, guildId);
  const xpNeededForCurrentLevel = 5 * (updatedRow.level ** 2 + 50 * updatedRow.level) + 100;
  const xpForPreviousLevels = updatedRow.level > 1 ? (5 * ((updatedRow.level - 1) ** 2 + 50 * (updatedRow.level - 1)) + 100) : 0;
  const currentLevelProgress = updatedRow.xp - xpForPreviousLevels;
  const totalXP = xpForPreviousLevels + currentLevelProgress;

  if ('level' in updatedRow && updatedRow.xp >= xpNeededForCurrentLevel) {
    lvldb.prepare('UPDATE level SET level = ?, xp = ?, totalxp = ? WHERE userid = ? AND guildid = ?').run(updatedRow.level + 1, updatedRow.xp - xpNeededForCurrentLevel, totalXP, userId, guildId);
    const level = updatedRow.level + 1;
    const channel = client.channels.cache.get(guildSettings.levelup);
    if(!channel) return;
    const message = await channel.send(`Congrats ${user}, you just reached level ${level}!`);

    function getRoleForLevel(guildId, levels) {
      const stmt = lvldb.prepare(`
        SELECT role_id FROM lvlroles 
        WHERE guild_id = ? AND levels = ?;
      `);
      const result = stmt.get(guildId, levels);
      return result ? result.role_id : null;
    }
    
    if (level) {
      const roleId = getRoleForLevel(message.guild.id, level);
      if (roleId) {
        const role = message.guild.roles.cache.get(roleId);
        if (role) {
          const member = message.guild.members.cache.get(userId);
          member.roles.add(role);
        }
      }
    }
  }
};

function getEnable(guildId) {
  const stmt = db.prepare('SELECT * FROM cfg_enable WHERE guild_id = ?');
  const row = stmt.get(guildId);
  return row;
}

function getGuildSettings(guildId) {
  const stmt = db.prepare('SELECT * FROM cfg_chid WHERE guild_id = ?');
  const row = stmt.get(guildId);
  return row;
}

报错原因

  1. message对象未正确传入:报错显示message是undefined,说明在bot.js第18行调用该模块时,没有传递有效的message参数。
  2. 逻辑未适配Slash Commands:原代码基于传统messageCreate事件设计,而Slash Commands使用的是interactionCreate事件,交互对象为Interaction而非Message,不存在message.guild属性。

解决方案

方案1:保留传统消息事件(兼容旧逻辑)

如果仍需支持普通消息触发等级系统,修改模块调用逻辑,先过滤非服务器消息:

// 在bot.js中修改调用代码
client.on('messageCreate', async (message) => {
  // 跳过私信消息,避免message.guild为undefined
  if (!message.guild) return;
  // 调用等级模块
  require('./src/functions/database/level.js')(client, message);
});

方案2:重构代码适配Slash Commands

如果已完全迁移到Slash Commands,修改等级模块以支持Interaction对象:

const config = require('../../../config/config');
const db = require('./cfgdb');
const lvldb = require('./lvldb');

// 兼容Message和Interaction对象,优先处理Interaction
module.exports = async (client, context) => {
  // 获取服务器对象,非服务器环境直接返回
  const guild = context.guild || (context.message?.guild);
  if (!guild) return;

  const guildEnable = getEnable(guild.id);
  // 增加可选链避免guildEnable为undefined时报错
  if (guildEnable?.leveling !== 1) return;
  
  const guildSettings = getGuildSettings(guild.id);
  if (!guildSettings) return;

  // 获取用户对象,兼容Message和Interaction
  const user = context.user || context.author;
  if (user.bot) return;

  const userId = user.id;
  const guildId = guild.id;
  const username = user.username;

  // 获取成员对象,兼容Message和Interaction
  const member = context.member;
  const booster = guildSettings.boosterrole;

  let xp;
  // 增加可选链避免member为undefined时报错
  if(member?.roles.cache.has(booster)) {
    xp = Math.floor(Math.random() * (50 - 35 + 1) + 35);
  } else {
    xp = Math.floor(Math.random() * (20 - 15 + 1) + 15);
  }

  const row = lvldb.prepare('SELECT * FROM level WHERE userid = ? AND guildid = ?').get(userId, guildId);

  if (!row || !('level' in row)) {
    lvldb.prepare('INSERT INTO level (userid, guildid, username, xp, totalxp) VALUES (?, ?, ?, ?, ?)').run(userId, guildId, username, xp, xp);
  } else {
    lvldb.prepare('UPDATE level SET xp = ?, totalxp = ? WHERE userid = ? AND guildid = ?').run(row.xp + xp, row.totalxp + xp, userId, guildId);
  }

  const updatedRow = lvldb.prepare('SELECT * FROM level WHERE userid = ? AND guildid = ?').get(userId, guildId);
  if (!updatedRow) return; // 防止数据查询失败

  const xpNeededForCurrentLevel = 5 * (updatedRow.level ** 2 + 50 * updatedRow.level) + 100;
  const xpForPreviousLevels = updatedRow.level > 1 ? (5 * ((updatedRow.level - 1) ** 2 + 50 * (updatedRow.level - 1)) + 100) : 0;
  const currentLevelProgress = updatedRow.xp - xpForPreviousLevels;
  const totalXP = xpForPreviousLevels + currentLevelProgress;

  if ('level' in updatedRow && updatedRow.xp >= xpNeededForCurrentLevel) {
    lvldb.prepare('UPDATE level SET level = ?, xp = ?, totalxp = ? WHERE userid = ? AND guildid = ?').run(updatedRow.level + 1, updatedRow.xp - xpNeededForCurrentLevel, totalXP, userId, guildId);
    const level = updatedRow.level + 1;
    const channel = client.channels.cache.get(guildSettings.levelup);
    if(!channel) return;
    
    // 发送升级提示
    const sendMessage = await channel.send(`恭喜 ${user},你升级到${level}级啦!`);

    function getRoleForLevel(guildId, levels) {
      const stmt = lvldb.prepare(`
        SELECT role_id FROM lvlroles 
        WHERE guild_id = ? AND levels = ?;
      `);
      const result = stmt.get(guildId, levels);
      return result ? result.role_id : null;
    }
    
    if (level) {
      const roleId = getRoleForLevel(guild.id, level);
      if (roleId) {
        const role = guild.roles.cache.get(roleId);
        // 确保角色和成员都存在再添加
        if (role && member) {
          member.roles.add(role);
        }
      }
    }
  }
};

function getEnable(guildId) {
  const stmt = db.prepare('SELECT * FROM cfg_enable WHERE guild_id = ?');
  const row = stmt.get(guildId);
  return row;
}

function getGuildSettings(guildId) {
  const stmt = db.prepare('SELECT * FROM cfg_chid WHERE guild_id = ?');
  const row = stmt.get(guildId);
  return row;
}

方案3:修改模块调用逻辑(针对Slash Commands)

在bot.js中修改interactionCreate事件的调用代码:

client.on('interactionCreate', async (interaction) => {
  // 处理其他交互逻辑(如命令处理)...
  
  // 调用等级模块,传入interaction对象
  require('./src/functions/database/level.js')(client, interaction);
});

内容的提问来源于stack exchange,提问作者TechXplore

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 08:37:06