Discord斜杠命令注册时出现TypeError: Cannot read properties of undefined (reading 'toJSON')错误排查
从你的描述和打印的CommandStore内容来看,问题的根源很明确:你的命令对象(BiodataCommand)并没有data属性,所以当你尝试调用command.data.toJSON()时,自然会抛出“无法读取undefined的toJSON属性”的错误。
结合你用的是Sapphire框架(从CommandStore、AliasPiece这些标识能看出来),我来帮你一步步排查修复:
1. 为什么会出现这个错误?
从你打印的BiodataCommand详情可以看到,你的命令类里只有applicationCommandRegistry但没有data字段,而你注册命令的代码却在尝试访问command.data——这完全不匹配。
Sapphire框架的命令类默认不会自动生成data属性,这个属性需要你自己在命令类里定义,或者你需要改用框架提供的命令注册方式,而不是直接用discord.js的rest.put逻辑硬套。
2. 修复步骤:先修正你的命令类
首先,你需要把biodata.js的命令类改成Sapphire框架下支持斜杠命令的正确写法,这里提供两种常用方式:
方式一:直接定义data属性(推荐用于需要手动批量注册的场景)
这种方式会给命令类添加data属性,刚好匹配你原来的注册代码逻辑:
const { Command } = require('@sapphire/framework'); const { SlashCommandBuilder } = require('discord.js'); class BiodataCommand extends Command { constructor(context, options) { super(context, { ...options, description: 'Send biodata form message' }); } // 定义data属性,返回SlashCommandBuilder实例 get data() { return new SlashCommandBuilder() .setName(this.name) .setDescription(this.description); } // 斜杠命令的执行逻辑 async chatInputRun(interaction) { await interaction.reply('正在生成 biodata 表单...'); // 这里写你的命令具体逻辑 } } module.exports = { BiodataCommand };
方式二:用Sapphire内置的registerApplicationCommands方法
这是Sapphire框架推荐的命令注册方式,不需要手动处理rest.put,框架会帮你自动注册:
const { Command } = require('@sapphire/framework'); class BiodataCommand extends Command { constructor(context, options) { super(context, { ...options, description: 'Send biodata form message' }); } // 让Sapphire自动注册斜杠命令 registerApplicationCommands(registry) { registry.registerChatInputCommand((builder) => builder.setName(this.name).setDescription(this.description) ); } async chatInputRun(interaction) { await interaction.reply('正在生成 biodata 表单...'); } } module.exports = { BiodataCommand };
如果用这种方式,你只需要确保Sapphire框架的API插件(@sapphire/plugin-api)已经正确配置,框架会自动处理命令的注册和同步,不需要你自己写rest.put的代码。
3. 调整你的注册代码(如果坚持手动注册)
如果你一定要用自己写的rest.put逻辑,那在修正命令类添加data属性之后,你的原有注册代码就能正常工作了。不过可以加个容错判断,避免其他命令出问题:
try { const commandStore = client.stores.get('commands'); console.log(commandStore); const commands = commandStore.map(command => { if (!command.data) { throw new Error(`命令 ${command.name} 未定义data属性,请检查命令类写法`); } return command.data.toJSON(); }); console.log(`Registering ${commands.length} commands...`); await rest.put(Routes.applicationCommands(client.user.id), { body: commands }); console.log('Commands registered successfully.'); } catch (error) { console.error('Error during command registration:', error); }
4. 额外提醒:Sapphire框架的自动注册能力
其实你完全不需要手动写rest.put的代码,Sapphire的@sapphire/plugin-api插件可以自动帮你同步全局/服务器级的斜杠命令,只需要在框架初始化时配置好插件即可,这样能避免很多手动注册的坑。
内容来源于stack exchange




