Discord.js v14取消并重试模态框提交后出现未知交互错误
问题原因分析
- Collector超时未捕获:用户点击【Cancel】关闭模态框时,Discord不会触发
modalSubmit事件,第一个awaitModalSubmit收集器会一直等待至超时,抛出InteractionCollectorError且未被捕获,导致报错。 - 多收集器交互冲突:第一个收集器未超时前,用户再次打开模态框并提交时,因原代码使用固定
customId,第一个收集器的filter会捕获到该提交交互(用户ID和customId均匹配),提前执行i.deferReply(),但该交互实际属于第二个收集器,后续处理时因交互已被操作/失效触发DiscordAPIError[10062]。 - Filter内的错误操作:在
filter中调用deferReply逻辑错误,无论filter是否返回true,该操作都会执行,导致不必要的交互回复,引发冲突。
解决方案
1. 为每个模态框生成唯一CustomId
避免多个收集器监听同一customId的交互,防止互相干扰。可通过时间戳或随机字符串生成唯一ID。
2. 用try/catch捕获收集器超时错误
忽略超时导致的InteractionCollectorError,避免未捕获异常扩散。
3. 将交互回复移至收集器结果处理阶段
不在filter内执行回复操作,确保只有符合条件的交互才会被处理。
修正后的代码示例
// 生成唯一的模态框customId const modalCustomId = `echomodal-${Date.now()}`; await interaction.showModal( new ModalBuilder() .setTitle("Echo Modal") .setCustomId(modalCustomId) .setComponents([ new ActionRowBuilder<TextInputBuilder>().addComponents([ new TextInputBuilder() .setCustomId("echomodaltext") .setLabel("Echo Text") .setStyle(TextInputStyle.Short), ]), ]) ); try { const result = await interaction.awaitModalSubmit({ filter: (i) => { // 仅匹配当前用户与当前模态框的唯一customId return i.user.id === interaction.user.id && i.customId === modalCustomId; }, time: 60_000, }); // 处理提交的模态框交互 await result.deferReply(); await result.editReply(result.fields.getTextInputValue("echomodaltext")); } catch (error) { // 忽略收集器超时错误,其他异常按需处理 if (error.name === 'InteractionCollectorError' && error.message.includes('time')) { return; } throw error; }
额外说明
- 生成唯一
customId时,也可使用crypto.randomUUID()生成更随机的字符串(需引入Node.js的crypto模块)。 - 目前Discord官方未提供
modalCancel事件,无法直接监听用户关闭模态框的操作,只能通过收集器超时间接判断用户未提交内容。
内容的提问来源于stack exchange,提问作者Step
相关产品推荐
相关产品推荐

