Discord.js v14 TypeError:无法读取undefined的'commands'属性求助
Discord.js v14 重载命令时出现TypeError问题排查
错误信息
TypeError: Cannot read properties of undefined (reading 'commands') at loadCommands (/home/runner/tester/handlers/commandHandler.js:19:14) at Object.execute (/home/runner/tester/commands/owner/reload.js:33:11) at Client.<anonymous> (/home/runner/tester/index.js:58:17) at Client.emit (node:events:513:28) at Client.emit (node:domain:489:12) at InteractionCreateAction.handle (/home/runner/tester/node_modules/discord.js/src/client/actions/InteractionCreate.js:97:12) at module.exports [as INTERACTION_CREATE] (/home/runner/tester/node_modules/discord.js/src/client/websocket/handlers/INTERACTION_CREATE.js:4:36) at WebSocketManager.handlePacket (/home/runner/tester/node_modules/discord.js/src/client/websocket/WebSocketManager.js:352:31) at WebSocketShard.onPacket (/home/runner/tester/node_modules/discord.js/src/client/websocket/WebSocketShard.js:494:22)
涉及代码文件
commandHandler.js
function loadCommands(client) { const ascii = require("ascii-table"); const fs = require("fs"); const table = new ascii().setHeading("File Name", "Status"); require("colors"); let commandsArray = []; const commandsFolder = fs.readdirSync("./commands"); for (const folder of commandsFolder) { const commandFiles = fs .readdirSync(`./commands/${folder}`) .filter((file) => file.endsWith(".js")); for (const file of commandFiles) { const commandFile = require(`../commands/${folder}/${file}`); const properties = { folder, ...commandFile }; client.commands.set(commandFile.data.name, properties); commandsArray.push(commandFile.data.toJSON()); table.addRow(file, "Loaded"); continue; } } client.application.commands.set(commandsArray); return console.log(table.toString(), "\n[+]".green + " Loaded Commands"); } module.exports = { loadCommands };
reload.js
const { Client, SlashCommandBuilder, EmbedBuilder } = require("discord.js"); const { loadCommands } = require("../../handlers/commandHandler"); const { loadEvents } = require("../../handlers/eventHandler"); module.exports = { data: new SlashCommandBuilder() .setName('reload') .setDescription('Reload your commands or events.') .addSubcommand(subcommand => subcommand.setName('commands') .setDescription('Reload your commands.') ) .addSubcommand(subcommand => subcommand.setName('events') .setDescription('Reload your events.') ), async execute(interaction, client) { const { user } = interaction; if (user.id !== "217414221728710656") return interaction.reply({ embeds: [new EmbedBuilder() .setColor('#2f3136') .setDescription('This command is only for the bot developer!')], ephemeral: true }) const sub = interaction.options.getSubcommand() const embed = new EmbedBuilder() .setTitle('Developer') .setColor('#2f3136') switch (sub) { case "commands": { loadCommands(client) interaction.reply({ embeds: [embed.setDescription('Commands reloaded!')] }) console.log(`${user} has reloaded the bot commands.`) } break; case "events": { loadEvents(client) interaction.reply({ embeds: [embed.setDescription('Events reloaded!')] }) console.log(`${user} has reloaded the bot events.`) } break; } } }
index.js
const { Client, Collection, Events, GatewayIntentBits, Partials, ActivityType } = require('discord.js'); require("colors"); const fs = require('node:fs'); const path = require('node:path'); const { token } = require('./config.json'); const client = new Client({ intents: [GatewayIntentBits.Guilds] }); client.commands = new Collection(); const foldersPath = path.join(__dirname, 'commands'); const commandFolders = fs.readdirSync(foldersPath); for (const folder of commandFolders) { const commandsPath = path.join(foldersPath, folder); const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js')); for (const file of commandFiles) { const filePath = path.join(commandsPath, file); const command = require(filePath); if ('data' in command && 'execute' in command) { client.commands.set(command.data.name, command); } else { console.log(`[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.`); } } } const eventsPath = path.join(__dirname, 'events'); const eventFiles = fs.readdirSync(eventsPath).filter(file => file.endsWith('.js')); for (const file of eventFiles) { const filePath = path.join(eventsPath, file); const event = require(filePath); if (event.once) { client.once(event.name, (...args) => event.execute(...args)); } else { client.on(event.name, (...args) => event.execute(...args)); } } const { loadCommands } = require("./handlers/commandHandler.js"); const { loadEvents } = require("./handlers/eventHandler.js"); client.once(Events.ClientReady, () => { console.log(`--------------------------------------------------------`) console.log("ඞ".red + " sus") console.log(`--------------------------------------------------------`) console.log( `Logged in as: ${client.user.tag.green} |`, `User ID: ${client.user.id.green}`, ); client.user.setActivity("Duck ASMR", {type: ActivityType.Streaming, url: "https://www.twitch.tv/dashducks" }); console.log(`--------------------------------------------------------`) console.log(`Current Servers In:`) console.log(``) client.guilds.cache.forEach((guild) => { console.log(` - ${guild.name.blue}`); }); console.log(`--------------------------------------------------------`) }); client.on(Events.InteractionCreate, async interaction => { if (!interaction.isChatInputCommand()) return; const command = interaction.client.commands.get(interaction.commandName); if (!command) { console.error(`No command matching ${interaction.commandName} was found.`); return; } try { await command.execute(interaction); } catch (error) { console.error(error); if (interaction.replied || interaction.deferred) { await interaction.followUp({ content: 'There was an error while executing this command!', ephemeral: true }); } else { await interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true }); } } }); module.expots = client; client.login(token).then(() => { loadEvents(client); loadCommands(client); }) const express = require('express') const app = express(); const port = 2000; app.get('/', (req, res) => { res.send('Hello World! ☀️'); }) app.listen(port, () => { console.log(`- App webview active at http://localhost:${port}`) })
问题背景
开发Discord.js v14机器人复习JavaScript,实现命令与事件重载斜杠命令时触发上述错误,搜索类似问题未找到有效方案,需要错误排查帮助及相关方法学习。
错误原因及修复方案
核心原因
loadCommands函数中访问client.commands时,传入的client参数为undefined。追踪发现,reload.js的execute函数定义需要interaction和client两个参数,但index.js中调用execute时只传了interaction,导致client参数缺失。
修复步骤
- 修正
index.js中的命令调用
找到InteractionCreate事件中的command.execute调用,补充传入client参数:
try { await command.execute(interaction, client); } catch (error) {
- 修正
index.js中的笔误
文件末尾的module.expots = client;是拼写错误,改为:
module.exports = client;
(该笔误不直接导致当前错误,但可能引发其他未知问题)
- 添加参数合法性校验(可选)
在commandHandler.js的loadCommands函数开头添加校验,提前拦截非法参数:
function loadCommands(client) { if (!client || !client.commands) { throw new Error("Invalid client instance provided to loadCommands"); } // 原函数代码... }
错误排查思路
- 定位错误位置:从错误栈中找到出错代码行(
commandHandler.js:19),明确是client.commands访问失败,说明client为undefined或client.commands未初始化。 - 追踪参数来源:查看
loadCommands的调用方(reload.js的execute函数),确认client参数来自execute的入参。 - 检查参数传递链:回到
index.js的命令调用逻辑,发现调用execute时未传入client,导致参数缺失。 - 验证修复效果:修正后重新运行,测试重载命令是否正常工作。
内容的提问来源于stack exchange,提问作者Jonny
相关产品推荐
相关产品推荐

