Discord反应角色按钮报错:interaction.deferUpdate()非函数或交互失败
问题描述
我正在开发带按钮的反应角色消息,把角色处理逻辑放在单独文件里,确保重启后仍能运行,但遇到两个问题:
- 报错:
interaction.deferUpdate() is not a function - Discord端显示「此交互失败」,但角色已成功增减
创建消息的代码
const { ApplicationCommandType, ActionRowBuilder, ButtonBuilder, EmbedBuilder } = require('discord.js'); module.exports = { name: 'role', description: "reactionroles", cooldown: 3000, userPerms: ['Administrator'], botPerms: ['Administrator'], run: async (client, message, args) => { const getButtons = (toggle = false, choice) => { const row = new ActionRowBuilder().addComponents( new ButtonBuilder() .setLabel('member') .setCustomId('member') .setStyle(toggle == true && choice == 'blue' ? 'Secondary' : 'Primary') .setDisabled(toggle), new ButtonBuilder() .setLabel('member2') .setCustomId('member2') .setStyle(toggle == true && choice == 'blue' ? 'Secondary' : 'Primary') .setDisabled(toggle), ); return row; } const embed = new EmbedBuilder() .setTitle('Wähle eine rolle') .setDescription('Wähle die rolle, die du gern haben möchtest') .setColor('Aqua') message.channel.send({ embeds: [embed], components: [getButtons()] }) .then((m) => { const collector = m.createMessageComponentCollector(); collector.on('collect', async (i) => { if (!i.isButton()) return; await i.deferUpdate(); }); }); } };
角色处理代码
const fs = require('fs'); const chalk = require('chalk') var AsciiTable = require('ascii-table') var table = new AsciiTable() const discord = require("discord.js"); table.setHeading('Events', 'Stats').setBorder('|', '=', "0", "0") module.exports = (client) => { client.ws.on("INTERACTION_CREATE", async (i) => { let guild = client.guilds.cache.get('934096845762879508'); let member = await guild.members.fetch(i.member.user.id) let role = guild.roles.cache.find(role => role.name === i.data.custom_id); if (!member.roles.cache.has(role.id)) { member.roles.add(role); } else { member.roles.remove(role); } return i.deferUpdate() }) };
问题原因及修复方案
1. interaction.deferUpdate() is not a function 报错原因
你用client.ws.on("INTERACTION_CREATE")拿到的i是Discord底层WebSocket原始数据对象,不是discord.js封装的标准Interaction实例,自然没有deferUpdate()这类封装方法。
2. 「此交互失败」的原因
- 你同时用了两种交互处理逻辑:消息组件收集器(
createMessageComponentCollector)和WebSocket事件,导致交互被重复触发,其中一个处理流程没有正确响应Discord的交互回调。 - WebSocket事件里的角色操作没加
await异步等待,且调用了不存在的方法,导致Discord在3秒内没收到合法响应,直接判定交互失败。
修复步骤
步骤1:移除重复的交互处理
删掉创建消息代码里的收集器逻辑,因为你已经在单独文件处理交互:
const { ApplicationCommandType, ActionRowBuilder, ButtonBuilder, EmbedBuilder } = require('discord.js'); module.exports = { name: 'role', description: "reactionroles", cooldown: 3000, userPerms: ['Administrator'], botPerms: ['Administrator'], run: async (client, message, args) => { const getButtons = (toggle = false, choice) => { const row = new ActionRowBuilder().addComponents( new ButtonBuilder() .setLabel('member') .setCustomId('member') .setStyle(toggle == true && choice == 'blue' ? 'Secondary' : 'Primary') .setDisabled(toggle), new ButtonBuilder() .setLabel('member2') .setCustomId('member2') .setStyle(toggle == true && choice == 'blue' ? 'Secondary' : 'Primary') .setDisabled(toggle), ); return row; } const embed = new EmbedBuilder() .setTitle('Wähle eine rolle') .setDescription('Wähle die rolle, die du gern haben möchtest') .setColor('Aqua') // 直接发送消息,移除收集器 await message.channel.send({ embeds: [embed], components: [getButtons()] }); } };
步骤2:改用discord.js官方interactionCreate事件处理交互
放弃底层WebSocket事件,用discord.js封装的事件,拿到标准交互实例:
const { Events } = require('discord.js'); module.exports = (client) => { client.on(Events.InteractionCreate, async (interaction) => { // 只处理按钮交互 if (!interaction.isButton()) return; // 限定仅目标服务器生效 if (interaction.guildId !== '934096845762879508') return; try { // 先延迟更新,告知Discord已收到交互(必须在3秒内调用) await interaction.deferUpdate(); const role = interaction.guild.roles.cache.find(r => r.name === interaction.customId); if (!role) return; const member = interaction.member; if (member.roles.cache.has(role.id)) { await member.roles.remove(role); } else { await member.roles.add(role); } } catch (error) { console.error('角色处理出错:', error); // 出错时给用户私密提示(可选) if (!interaction.replied && !interaction.deferred) { await interaction.reply({ content: '处理角色时出现错误', ephemeral: true }); } } }); };
关键注意点
- 所有异步操作(增减角色、发送响应)必须加
await,确保流程顺序执行。 - 交互触发后必须在3秒内调用
deferUpdate()或reply(),否则Discord会判定交互失败。 - 使用discord.js封装的事件和对象,避免直接操作底层WebSocket数据,减少兼容性问题。
内容的提问来源于stack exchange,提问作者Fheliks
相关产品推荐
相关产品推荐

