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

Discord.js v14模态框报错:Cannot read properties of undefined (reading 'getTextInputValue')

问题分析与修复方案

错误原因

你写的代码在按钮交互的回调里,弹出模态框后直接调用interaction.fields.getTextInputValue("reason")——这时候用户还没提交模态框,当前的按钮交互对象里根本没有fields属性,自然会报“Cannot read properties of undefined”的错误。模态框的提交是一个独立的交互事件,和按钮点击不是同一个interaction实例,必须单独监听处理。

修复步骤

  1. 拆分逻辑:按钮点击只负责弹出模态框,不处理后续的输入值读取和嵌入更新
  2. 新增模态框提交的处理分支,监听isModalSubmit()类型的交互
  3. 在模态框提交回调里,获取输入值、找到对应建议消息、更新嵌入内容

修复后的完整代码

const { PermissionFlagsBits, EmbedBuilder, TextInputStyle, TextInputBuilder, ModalBuilder, ActionRowBuilder } = require("discord.js");
const suggestionSchema = require("../../Models/Suggestion");

module.exports = {
    name: "interactionCreate",
    async execute(interaction) {
        const { member, guildId, customId, message } = interaction;

        // 处理按钮交互:弹出模态框
        if (interaction.isButton()) {
            if (customId === "suggest-accept" || customId === "suggest-decline") {
                if (!member.permissions.has(PermissionFlagsBits.Administrator))
                    return interaction.reply({ content: "No permissions!", ephemeral: true });

                // 先验证数据存在
                const data = await suggestionSchema.findOne({ GuildID: guildId, MessageID: message.id });
                if (!data)
                    return interaction.reply({ content: "No data was found.", ephemeral: true });

                const embed = message.embeds[0];
                if (!embed)
                    return interaction.reply({ content: "No embed was found.", ephemeral: true });

                if (customId === "suggest-accept") {
                    // 构建并弹出模态框,把消息ID放进模态框ID方便后续关联
                    const modal = new ModalBuilder()
                        .setTitle('Accept Suggestion')
                        .setCustomId(`accept-modal-${message.id}`);

                    const reasonInput = new TextInputBuilder()
                        .setCustomId('reason')
                        .setRequired(true)
                        .setLabel('Accept Reason')
                        .setStyle(TextInputStyle.Short);

                    const actionRow = new ActionRowBuilder().addComponents(reasonInput);
                    modal.addComponents(actionRow);

                    await interaction.showModal(modal);
                } else if (customId === "suggest-decline") {
                    // 拒绝逻辑直接处理
                    embed.data.fields[2] = { name: "Status", value: "Declined", inline: true };
                    const declinedEmbed = EmbedBuilder.from(embed).setColor("Red");

                    await message.edit({ embeds: [declinedEmbed] });
                    await interaction.reply({ content: "Suggestion declined.", ephemeral: true });
                }
            }
            return;
        }

        // 处理模态框提交交互
        if (interaction.isModalSubmit()) {
            // 匹配接受建议的模态框ID
            if (customId.startsWith("accept-modal-")) {
                if (!member.permissions.has(PermissionFlagsBits.Administrator))
                    return interaction.reply({ content: "No permissions!", ephemeral: true });

                // 从模态框ID里提取原建议消息的ID
                const messageId = customId.split("-")[2];
                const targetMessage = await interaction.channel.messages.fetch(messageId).catch(() => null);
                if (!targetMessage)
                    return interaction.reply({ content: "Original suggestion message not found.", ephemeral: true });

                // 获取用户输入的理由
                const reason = interaction.fields.getTextInputValue("reason");

                // 更新嵌入内容
                const embed = targetMessage.embeds[0];
                embed.data.fields[2] = { name: "Status", value: "Accepted", inline: true };
                embed.data.fields[3] = { name: "Reason", value: reason, inline: true };
                const acceptedEmbed = EmbedBuilder.from(embed).setColor("Green");

                await targetMessage.edit({ embeds: [acceptedEmbed] });
                await interaction.reply({ content: "Suggestion accepted successfully.", ephemeral: true });

                // 可选:更新数据库里的状态和理由
                await suggestionSchema.findOneAndUpdate(
                    { GuildID: guildId, MessageID: messageId },
                    { Status: "Accepted", Reason: reason }
                );
            }
        }
    }
};

关键改动说明

  • 把按钮交互和模态框提交交互分开处理,各自对应isButton()和isModalSubmit()类型判断
  • 模态框的自定义ID带上了原建议消息的ID,提交时能准确找到要更新的目标消息
  • 仅在模态框提交回调里读取interaction.fields,此时用户已完成提交,fields属性有效
  • 用await处理所有异步操作,避免回调嵌套和异步顺序问题
  • 新增数据库更新的可选逻辑,确保建议数据状态一致

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 15:15:27