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

Discord.js交互问卷报错:无法读取null的createMessageCollector属性

问题分析与修复方案

核心错误原因

  1. interaction.channel为空值:用户在DM中点击GBAStart按钮时,interaction.channel无法正确获取DM频道对象,导致调用createMessageCollector时抛出空值读取错误。
  2. 未定义变量引用:GBAStart分支中使用的message.author.id属于messageCreate事件的局部变量,此处无法访问,会导致消息过滤逻辑失效。
  3. 收集器停止条件错误:原代码中counter == questions.length + 1的判断会导致多等待一次无效回复,应该在所有问题发送完毕后立即停止收集器。

修复后的完整代码

// Main requirements
const { CHANNEL_SSU, CHANNEL_ROLESEL, BOT_PREFIX, ROLE_DEV } = require('../../config.json')
const commandName = 'gba'

// Optional Requirements
const { MessageEmbed, MessageActionRow, MessageButton, MessageCollector } = require('discord.js')

// Main Code
module.exports = client => {
    client.on('messageCreate', async message => {
        if (message.author.bot) return;
        if (!message.content.toLowerCase().startsWith(BOT_PREFIX)) return;

        const command = message.content.split(' ')
        const args = message.content.substring(1).split(' ')

        if (command.toString().toLowerCase().replace(BOT_PREFIX, '').startsWith(commandName)) {
            if (!message.member.roles.cache.has(ROLE_DEV)) return message.reply("Only Developers can use this command!")

            const buttonsRow1 = new MessageActionRow().addComponents(
                new MessageButton()
                .setCustomId('GBAempty1')
                .setLabel('  ')
                .setStyle('SECONDARY')
                .setDisabled(true),
                new MessageButton()
                .setCustomId('GBA')
                .setLabel('Appeal')
                .setStyle('DANGER')
                .setDisabled(false),
                new MessageButton()
                .setCustomId('GBAempty2')
                .setLabel('  ')
                .setStyle('SECONDARY')
                .setDisabled(true)
            )

            const GBAEmbed = new MessageEmbed()
            .setTitle('Appeal Your Game Ban!')
            .setColor('DARK_BLUE')
            .setFooter({ text: 'ASRP | System Bot' })
            .setThumbnail(message.guild.iconURL({ dynamic: true, size: 512 }))

            message.delete()
            message.channel.send({ embeds: [GBAEmbed], components: [buttonsRow1] })
        }
    })
    client.on(`interactionCreate`, async (interaction) => {
        if (!interaction.isButton) return
        
        if (interaction.customId == 'GBA') {
            await interaction.deferReply({
                ephemeral: true
            })

            const appealEmbed = new MessageEmbed()
                .setTitle(`Started Appeal.`)
                .setDescription(`Please check your DM for the appeal.`)
                .setFooter({ text: 'ASRP | System Bot' })
                .setTimestamp()
                .setColor('ORANGE')

            await interaction.editReply({ embeds: [appealEmbed], ephemeral: true })

            const user = interaction.user;

            const buttonsRow2 = new MessageActionRow().addComponents(
                new MessageButton()
                .setCustomId('GBAempty3')
                .setLabel('  ')
                .setStyle('SECONDARY')
                .setDisabled(true),
                new MessageButton()
                .setCustomId('GBAStart')
                .setLabel('Appeal')
                .setStyle('DANGER')
                .setDisabled(false),
                new MessageButton()
                .setCustomId('GBAempty4')
                .setLabel('  ')
                .setStyle('SECONDARY')
                .setDisabled(true)
            )

            const GBAstart = new MessageEmbed()
                .setTitle(`Start Appeal.`)
                .setDescription(`Press 'Start' to start appealing your game ban.`)
                .setFooter({ text: 'ASRP | System Bot' })
                .setThumbnail(interaction.guild.iconURL({ dynamic: true, size: 512 }))

            await user.send({ embeds: [GBAstart], components: [buttonsRow2] })
        }

        if (interaction.customId == 'GBAStart') {
            await interaction.deferReply({ ephemeral: true });
            await interaction.editReply("Appeal started! Check your DM for questions.");

            const questions = [
                "How old are you?",
                "How are you?",
                "What time is it for you?"
            ]

            let counter = 0
            const targetUser = interaction.user;
            const dmChannel = await targetUser.createDM();

            const filter = m => m.author.id === targetUser.id;
            const collector = dmChannel.createMessageCollector({ filter, time: 1000 * 1200, max: questions.length });
            
            await dmChannel.send(questions[counter++]);

            collector.on('collect', (m) => {
                if (counter < questions.length) {
                    m.reply(questions[counter++]);
                }
                if (counter === questions.length) {
                    collector.stop();
                }
            });

            collector.on('end', collected => {
                console.log(`Collected ${collected.size} messages`);

                if (collected.size < questions.length) {
                    dmChannel.send("You didn't answer in time, please restart the appeal.");
                    return;
                }
          
                let counter = 0;
                collected.forEach((value) => {
                    console.log(questions[counter++], value.content);
                });
            });
        }
    })
}

关键修复点说明

  • 获取有效DM频道:使用interaction.user.createDM()确保获取到可用的DM频道对象,彻底解决interaction.channel为空的问题。
  • 修正过滤逻辑:用interaction.user.id替代未定义的message.author.id,保证只收集目标用户的回复。
  • 调整收集器停止时机:将停止条件改为counter === questions.length,确保所有问题回复完成后立即终止收集。
  • 优化交互提示:点击GBAStart后明确告知用户查看DM,提升操作体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 19:27:30