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

Discord.js 14.15.3交互已确认错误(40060)修复求助

修复DiscordAPIError[40060]: Interaction has already been acknowledged

问题原因

你的错误核心有两个:

  1. 交互超时未响应:创建工单转录(transcripts.createTranscript)可能耗时超过3秒,Discord要求所有交互必须在3秒内确认,超时后会自动标记为已确认,后续再调用submitted.update就会触发40060错误。
  2. 交互对象误用:你试图用模态框提交的交互(submitted)去更新原始按钮的消息,这是错误的用法,应该直接操作触发模态框的按钮消息(interaction.message)。

修复后的代码

const {
  ActionRowBuilder,
  EmbedBuilder,
  ButtonBuilder,
  WebhookClient,
  ModalBuilder,
  TextInputBuilder,
  TextInputStyle,
} = require('discord.js');
const transcripts = require('discord-html-transcripts');

module.exports = {
  data: {
    name: 'cerrarticket',
  },
  async execute(interaction, client, args) {
    const webhook = new WebhookClient({
      url: client.config.webhook.tickets,
    });

    if (!interaction.member.roles.cache.has(client.config.lf.staffRoleId)) {
      return interaction.reply({
        content: 'Only staff can use this!',
        ephemeral: true,
      });
    }

    const modal = new ModalBuilder()
      .setCustomId('closeticket')
      .setTitle('Ticket close form')
      .addComponents(
        new ActionRowBuilder().addComponents(
          new TextInputBuilder()
            .setCustomId('reason')
            .setLabel('Why do you want to close the ticket?')
            .setStyle(TextInputStyle.Paragraph),
        ),
      );

    await interaction.showModal(modal);

    const submitted = await interaction
      .awaitModalSubmit({
        time: 60000,
        filter: (i) => i.user.id === interaction.user.id,
      })
      .catch((err) => {
        return null;
      });

    if (submitted) {
      // 立即延迟响应,避免交互超时
      await submitted.deferReply({ ephemeral: true });

      const reason = submitted.fields.getTextInputValue('reason');
      const channel = submitted.channel;
      const ownerTicket = submitted.guild.members.cache.get(args[0]);

      // 执行耗时的转录创建操作
      const attachment = await transcripts.createTranscript(channel, {
        saveImages: true,
      });

      // 禁用原始按钮(操作触发模态框的按钮消息)
      await interaction.message.edit({
        components: [
          new ActionRowBuilder().addComponents(
            interaction.message.components[0].components.map(btn => 
              ButtonBuilder.from(btn).setDisabled(true)
            ),
          ),
        ],
      });

      // 发送处理成功的提示
      await submitted.followUp({
        content: 'The ticket has entered the closing process correctly!',
        ephemeral: true,
      });

      // 发送关闭倒计时消息
      await channel.send({
        embeds: [
          new EmbedBuilder()
            .setColor('#701196')
            .setDescription('The ticket will be closed in 5 seconds...'),
        ],
      });

      // 延迟删除频道
      setTimeout(async () => {
        if (channel) await channel.delete().catch(() => null);
      }, 5000);

      // 发送转录到webhook
      await webhook.send({
        content: '<:Vacio:1286828514770812948>',
        embeds: [
          new EmbedBuilder()
            .setColor('#701196')
            .setDescription(`# 📝 Transcript`)
            .setTimestamp()
            .addFields(
              {
                name: 'Ticket',
                value: `#${channel.name} (${channel.id})`,
              },
              {
                name: 'Panel',
                value: `${channel.name.split('-')[0].charAt(0).toUpperCase() + channel.name.split('-')[0].slice(1)}`,
              },
              {
                name: 'Owner',
                value: `**[@${ownerTicket.user.username}]** (${ownerTicket.user.id})\n<:Vacio:1286828514770812948>`,
              },
              {
                name: 'Moderator',
                value: `**[@${submitted.user.username}]** (${submitted.user.id})`,
              },
              {
                name: 'Reason',
                value: `${reason}`,
              },
            ),
        ],
        files: [attachment],
      }).catch(() => null);
    }
  },
};

关键修复点说明

  • 立即延迟响应:在拿到submitted后第一时间调用submitted.deferReply({ephemeral: true}),告诉Discord"我稍后再响应",避免3秒超时自动确认。
  • 修改原始按钮状态:用interaction.message.edit()替代submitted.update(),直接修改触发模态框的按钮消息,禁用按钮。
  • 异步操作顺序调整:把耗时的转录创建放在延迟响应之后,确保交互不会超时。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 22:34:59