I keep getting Unknown Interaction errors in my console.

I accidentally closed the last post. I have lots of people using my bot each day and there seems to always be Unknown Interaction errors when people use commands. I haven't been able to recreate this issue myself and it doesn't even happen 100% of the time (sometimes that code runs fine, and other times it throws that error). I don't really see what the problem is in my code. Refer to the image, the circled file is what this code is..
const { somethingWentWrong, noRedditCategories } = require("./commonMessages");
const { formatEmbedImage, formatRedditImage } = require("./formatDiscordImages");
const { retrieveImage } = require("./imageDatabaseHandler");
const { makeRedditRequest } = require("./makeRedditRequest");
const { fetchOrUpdateMember } = require("./queryDB");
const settings = require("../settings/clients/hentaicord.json");
const { memberData } = require("../mongoose");

async function retrieveHandler(interaction, type, category, isRepeat) {

let dbMember;
try { dbMember = await memberData.findOneAndUpdate({ discord_id: interaction.user.id }, {}, { upsert: true, new: true }); }
catch (error) { return console.error(error); }

let replyObject;
if(type === "reddit") {
if(!await noRedditCategories(interaction)) return; //does a premium status check before proceeding

let random_media = await makeRedditRequest(category);
if(random_media.success === false) return await somethingWentWrong(interaction);
random_media = random_media.data.data;

let format = await formatRedditImage(type, category);
if(format.success === false) return await somethingWentWrong(interaction);
format = format.data;

replyObject = { content: random_media.url, components: [ format.button ] };
}

else {
if(category === "random") {
let available_categories = settings.categories[type].filter(x => x !== "random");
category = available_categories[Math.floor(Math.random() * available_categories.length)];
}
let randomImage = await retrieveImage(type.toLowerCase(), category.toLowerCase());
if(randomImage.success == false) return await somethingWentWrong(interaction);
randomImage = randomImage.image;

let format = await formatEmbedImage(interaction, type, category, randomImage);
if(format.success === false) return await somethingWentWrong(interaction);
format = format.data;

replyObject = { embeds: [format.embed], components: [format.button] };
};

if(isRepeat === true && dbMember.toggles.replace_images === true) {
await interaction.update(replyObject).catch(console.error);
}

else {
await interaction.reply(replyObject).catch(console.error);
}

}


module.exports.retrieveHandler = retrieveHandler;
const { somethingWentWrong, noRedditCategories } = require("./commonMessages");
const { formatEmbedImage, formatRedditImage } = require("./formatDiscordImages");
const { retrieveImage } = require("./imageDatabaseHandler");
const { makeRedditRequest } = require("./makeRedditRequest");
const { fetchOrUpdateMember } = require("./queryDB");
const settings = require("../settings/clients/hentaicord.json");
const { memberData } = require("../mongoose");

async function retrieveHandler(interaction, type, category, isRepeat) {

let dbMember;
try { dbMember = await memberData.findOneAndUpdate({ discord_id: interaction.user.id }, {}, { upsert: true, new: true }); }
catch (error) { return console.error(error); }

let replyObject;
if(type === "reddit") {
if(!await noRedditCategories(interaction)) return; //does a premium status check before proceeding

let random_media = await makeRedditRequest(category);
if(random_media.success === false) return await somethingWentWrong(interaction);
random_media = random_media.data.data;

let format = await formatRedditImage(type, category);
if(format.success === false) return await somethingWentWrong(interaction);
format = format.data;

replyObject = { content: random_media.url, components: [ format.button ] };
}

else {
if(category === "random") {
let available_categories = settings.categories[type].filter(x => x !== "random");
category = available_categories[Math.floor(Math.random() * available_categories.length)];
}
let randomImage = await retrieveImage(type.toLowerCase(), category.toLowerCase());
if(randomImage.success == false) return await somethingWentWrong(interaction);
randomImage = randomImage.image;

let format = await formatEmbedImage(interaction, type, category, randomImage);
if(format.success === false) return await somethingWentWrong(interaction);
format = format.data;

replyObject = { embeds: [format.embed], components: [format.button] };
};

if(isRepeat === true && dbMember.toggles.replace_images === true) {
await interaction.update(replyObject).catch(console.error);
}

else {
await interaction.reply(replyObject).catch(console.error);
}

}


module.exports.retrieveHandler = retrieveHandler;
The line console is referring to is the:
else {
await interaction.reply(replyObject).catch(console.error);
}
else {
await interaction.reply(replyObject).catch(console.error);
}
12 Replies
d.js toolkit
d.js toolkit9mo ago
- What's your exact discord.js npm list discord.js and node node -v version? - Not a discord.js issue? Check out #other-js-ts. - Consider reading #how-to-get-help to improve your question! - Explain what exactly your issue is. - Post the full error stack trace, not just the top part! - Show your code! - Issue solved? Press the button!
AJ
AJ9mo ago
could it be because im using await? should I do return interaction.reply() ?
d.js docs
d.js docs9mo ago
Common causes of DiscordAPIError[10062]: Unknown interaction: - Initial response took more than 3 seconds ➞ defer the response *. - Wrong interaction object inside a collector. - Two processes handling the same command (the first consumes the interaction, so it won't be valid for the other instance) * Note: you cannot defer modal or autocomplete value responses
AJ
AJ9mo ago
ah perfect thank you my bot gets rate limited by Discord regularly, do you think it's because of all of these unknown interaction errors? Bearing in mind, there's only about 1 per 10 to 30 seconds or so I do think it's something else but just asking
dlex
dlex9mo ago
Quick question, @Qjuh when i do deferReply am i able to change the bot is thinking text?
AJ
AJ9mo ago
Nah Discord API rate limit And by regularly, I mean like, at least 3 times per day It's a massive pain in the ass
dlex
dlex9mo ago
Chill out it's a thread it ain't no plane
AJ
AJ9mo ago
@Qjuh can you deferReply for a button interaction? I have a feature that replaces (update) the image instead of sending it separately (reply). This is the file that runs when that button is pressed:
const { checkHasVoted } = require("../../../../functions/commonMessages");
const { fetchOrUpdateMember } = require("../../../../functions/queryDB");
const { retrieveHandler } = require("../../../../functions/retrieveHandler");

module.exports = async (interaction) => {

try {
let dbMember = await fetchOrUpdateMember({ discord_id: interaction.user.id }, { }, { upsert: true });
if(dbMember.data.toggles.replace_images === true) await interaction.deferUpdate();
else await interaction.deferReply();
}
catch (error) { return console.error(error) };

let hasVoted = await checkHasVoted(interaction);
if(!hasVoted.success && hasVoted === false) return;

const options = interaction.customId.split(".");
const type = options[1];
const category = options[2];

return await retrieveHandler(interaction, type, category, true, dbMember);

}
const { checkHasVoted } = require("../../../../functions/commonMessages");
const { fetchOrUpdateMember } = require("../../../../functions/queryDB");
const { retrieveHandler } = require("../../../../functions/retrieveHandler");

module.exports = async (interaction) => {

try {
let dbMember = await fetchOrUpdateMember({ discord_id: interaction.user.id }, { }, { upsert: true });
if(dbMember.data.toggles.replace_images === true) await interaction.deferUpdate();
else await interaction.deferReply();
}
catch (error) { return console.error(error) };

let hasVoted = await checkHasVoted(interaction);
if(!hasVoted.success && hasVoted === false) return;

const options = interaction.customId.split(".");
const type = options[1];
const category = options[2];

return await retrieveHandler(interaction, type, category, true, dbMember);

}
It doesn't seem to be working for deferUpdate() do you know what the problem could be? Ah yeah sorry It outputs unknown interaction in my console when pressed and says 'Failed to respond' or whatever
DiscordAPIError[10062]: Unknown interaction
at handleErrors (C:\Users\Andrew\Documents\GitHub\thp-services\node_modules\@discordjs\rest\dist\index.js:687:13)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async BurstHandler.runRequest (C:\Users\Andrew\Documents\GitHub\thp-services\node_modules\@discordjs\rest\dist\index.js:786:23)
at async _REST.request (C:\Users\Andrew\Documents\GitHub\thp-services\node_modules\@discordjs\rest\dist\index.js:1218:22)
at async ButtonInteraction.deferUpdate (C:\Users\Andrew\Documents\GitHub\thp-services\node_modules\discord.js\src\structures\interfaces\InteractionResponses.js:200:5)
at async module.exports (C:\Users\Andrew\Documents\GitHub\thp-services\clients\hentaicord\events\buttons\repeatImageRetrieval.js:9:59) {
requestBody: { files: undefined, json: { type: 6 } },
rawError: { message: 'Unknown interaction', code: 10062 },
code: 10062,
status: 404,
method: 'POST',
url: 'https://discord.com/api/v10/interactions/1191504750903050270/aW50ZXJhY3Rpb246MTE5MTUwNDc1MDkwMzA1MDI3MDpvNlBpcUdUVFg0VUFybUNKMVVQckJqd1AwMmk4THhFOGVwMm9IQlFHOGFRZTZwNlYyQ01lRVFqaVdpWTJwN1F6cExBY3RYZEJqM2FCTG1DQmJaSHpncElDZ0puMzNEb0pZVHNUS2cwalcwTG00VXo4NzdPNVJJeHM0MGViTWxVMw/callback'
}
DiscordAPIError[10062]: Unknown interaction
at handleErrors (C:\Users\Andrew\Documents\GitHub\thp-services\node_modules\@discordjs\rest\dist\index.js:687:13)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async BurstHandler.runRequest (C:\Users\Andrew\Documents\GitHub\thp-services\node_modules\@discordjs\rest\dist\index.js:786:23)
at async _REST.request (C:\Users\Andrew\Documents\GitHub\thp-services\node_modules\@discordjs\rest\dist\index.js:1218:22)
at async ButtonInteraction.deferUpdate (C:\Users\Andrew\Documents\GitHub\thp-services\node_modules\discord.js\src\structures\interfaces\InteractionResponses.js:200:5)
at async module.exports (C:\Users\Andrew\Documents\GitHub\thp-services\clients\hentaicord\events\buttons\repeatImageRetrieval.js:9:59) {
requestBody: { files: undefined, json: { type: 6 } },
rawError: { message: 'Unknown interaction', code: 10062 },
code: 10062,
status: 404,
method: 'POST',
url: 'https://discord.com/api/v10/interactions/1191504750903050270/aW50ZXJhY3Rpb246MTE5MTUwNDc1MDkwMzA1MDI3MDpvNlBpcUdUVFg0VUFybUNKMVVQckJqd1AwMmk4THhFOGVwMm9IQlFHOGFRZTZwNlYyQ01lRVFqaVdpWTJwN1F6cExBY3RYZEJqM2FCTG1DQmJaSHpncElDZ0puMzNEb0pZVHNUS2cwalcwTG00VXo4NzdPNVJJeHM0MGViTWxVMw/callback'
}
line 9 is the deferUpdate() one yeah for additional context, this is my retrieveHandler function which you seen earlier:
const { somethingWentWrong, noRedditCategories } = require("./commonMessages");
const { formatEmbedImage, formatRedditImage } = require("./formatDiscordImages");
const { retrieveImage } = require("./imageDatabaseHandler");
const { makeRedditRequest } = require("./makeRedditRequest");
const { fetchOrUpdateMember } = require("./queryDB");
const settings = require("../settings/clients/hentaicord.json");
const { memberData } = require("../mongoose");

async function retrieveHandler(interaction, type, category, isRepeat, dbMember) {

let replyObject;
if(type === "reddit") {
if(!await noRedditCategories(interaction, true)) return; //does a premium status check before proceeding

let random_media = await makeRedditRequest(category);
if(random_media.success === false) return await somethingWentWrong(interaction, true);
random_media = random_media.data.data;

let format = await formatRedditImage(type, category);
if(format.success === false) return await somethingWentWrong(interaction, true);
format = format.data;

replyObject = { content: random_media.url, components: [ format.button ] };
}

else {
if(category === "random") {
let available_categories = settings.categories[type].filter(x => x !== "random");
category = available_categories[Math.floor(Math.random() * available_categories.length)];
}
let randomImage = await retrieveImage(type.toLowerCase(), category.toLowerCase());
if(randomImage.success == false) return await somethingWentWrong(interaction, true);
randomImage = randomImage.image;

let format = await formatEmbedImage(interaction, type, category, randomImage);
if(format.success === false) return await somethingWentWrong(interaction, true);
format = format.data;

replyObject = { embeds: [format.embed], components: [format.button] };
};

if(isRepeat === true && dbMember.toggles.replace_images === true) {
return interaction.deferUpdate(replyObject).catch(console.error); //this could fail sometimes?
}

else {
return interaction.editReply(replyObject).catch(console.error);
}

}


module.exports.retrieveHandler = retrieveHandler;
const { somethingWentWrong, noRedditCategories } = require("./commonMessages");
const { formatEmbedImage, formatRedditImage } = require("./formatDiscordImages");
const { retrieveImage } = require("./imageDatabaseHandler");
const { makeRedditRequest } = require("./makeRedditRequest");
const { fetchOrUpdateMember } = require("./queryDB");
const settings = require("../settings/clients/hentaicord.json");
const { memberData } = require("../mongoose");

async function retrieveHandler(interaction, type, category, isRepeat, dbMember) {

let replyObject;
if(type === "reddit") {
if(!await noRedditCategories(interaction, true)) return; //does a premium status check before proceeding

let random_media = await makeRedditRequest(category);
if(random_media.success === false) return await somethingWentWrong(interaction, true);
random_media = random_media.data.data;

let format = await formatRedditImage(type, category);
if(format.success === false) return await somethingWentWrong(interaction, true);
format = format.data;

replyObject = { content: random_media.url, components: [ format.button ] };
}

else {
if(category === "random") {
let available_categories = settings.categories[type].filter(x => x !== "random");
category = available_categories[Math.floor(Math.random() * available_categories.length)];
}
let randomImage = await retrieveImage(type.toLowerCase(), category.toLowerCase());
if(randomImage.success == false) return await somethingWentWrong(interaction, true);
randomImage = randomImage.image;

let format = await formatEmbedImage(interaction, type, category, randomImage);
if(format.success === false) return await somethingWentWrong(interaction, true);
format = format.data;

replyObject = { embeds: [format.embed], components: [format.button] };
};

if(isRepeat === true && dbMember.toggles.replace_images === true) {
return interaction.deferUpdate(replyObject).catch(console.error); //this could fail sometimes?
}

else {
return interaction.editReply(replyObject).catch(console.error);
}

}


module.exports.retrieveHandler = retrieveHandler;
don't worry about the 'this coud fail sometimes?' comment, it needs removing ohhh weird, it works perfectly fine now, could be a bug? also here: well it's on the InteractionCreate file
const { Listener } = require(`gcommands`);
const { Events, EmbedBuilder } = require(`discord.js`);
const { fetchOrUpdateStatistics } = require("../../../functions/queryDB");
const date = require("../../../functions/currentDate");


new Listener ({
name: `InteractionCreate`,
event: Events.InteractionCreate,
once: false,

run: async (interaction) => {

if (interaction.isChatInputCommand()) {
var obj = { interaction: "slash_commands", toPush: { command: interaction.commandName } };
};

if (interaction.customId != undefined) {
const customID = interaction.customId.split(`.`)[0];

if (interaction.isButton()) {
try {
require(`./buttons/${customID}`)(interaction);
var obj = { interaction: "buttons", toPush: { button: customID } };
}
catch (error) { return; };
};

if (interaction.isModalSubmit()) {
try {
require(`./modals/${customID}`)(interaction);
var obj = { interaction: "modals", toPush:{ modal: customID }};
}
catch (error) { return; };
};

if (interaction.isAnySelectMenu()) {
try {
require(`./select menus/${customID}`)(interaction);
var obj = { interaction: "select_menus", toPush: { select_menu: customID } };
}
catch (error) { return; };
};

};


try {
await fetchOrUpdateStatistics(
{ date: String(date(`Europe/London`, `DD-MMM-YY`)) },
{ $push: { [`client.hentaicord.${process.env.NODE_ENV}.interactions.${obj.interaction}`]: obj.toPush } },
{ upsert: true }
);
}
catch (error) {
console.error(error);
}

}

});
const { Listener } = require(`gcommands`);
const { Events, EmbedBuilder } = require(`discord.js`);
const { fetchOrUpdateStatistics } = require("../../../functions/queryDB");
const date = require("../../../functions/currentDate");


new Listener ({
name: `InteractionCreate`,
event: Events.InteractionCreate,
once: false,

run: async (interaction) => {

if (interaction.isChatInputCommand()) {
var obj = { interaction: "slash_commands", toPush: { command: interaction.commandName } };
};

if (interaction.customId != undefined) {
const customID = interaction.customId.split(`.`)[0];

if (interaction.isButton()) {
try {
require(`./buttons/${customID}`)(interaction);
var obj = { interaction: "buttons", toPush: { button: customID } };
}
catch (error) { return; };
};

if (interaction.isModalSubmit()) {
try {
require(`./modals/${customID}`)(interaction);
var obj = { interaction: "modals", toPush:{ modal: customID }};
}
catch (error) { return; };
};

if (interaction.isAnySelectMenu()) {
try {
require(`./select menus/${customID}`)(interaction);
var obj = { interaction: "select_menus", toPush: { select_menu: customID } };
}
catch (error) { return; };
};

};


try {
await fetchOrUpdateStatistics(
{ date: String(date(`Europe/London`, `DD-MMM-YY`)) },
{ $push: { [`client.hentaicord.${process.env.NODE_ENV}.interactions.${obj.interaction}`]: obj.toPush } },
{ upsert: true }
);
}
catch (error) {
console.error(error);
}

}

});
InteractionCreate.js Im using gcommands aswell yeah that makes sense actually I don't really have a way around that it is haha I made a function to just retrieve the members but I dont think it's needed anymore. Soon to be removed in a future update it serves the exact same purpose of simply using collection.findOneAndUpdate() anyway, thanks for your help with this hey sorry, just another question @Qjuh Will interaction.showModal() still work when the interaction is deferred? for context, in my export it defers the reply, and then at the bottom (if checks are all successful) it'll show the modal
const { ModalBuilder, TextInputBuilder, TextInputStyle, ActionRowBuilder, EmbedBuilder, ButtonStyle, ButtonBuilder } = require("discord.js");
const ai_models = require("../../../../settings/ai-models.json");
const { fetchOrUpdateMember } = require("../../../../functions/queryDB");
const settings = require("../../../../settings/clients/hentaicord.json");
const { somethingWentWrong } = require("../../../../functions/commonMessages");
const links = require("../../../../settings/links.json");

module.exports = async (interaction) => {

await interaction.deferReply().catch(console.error);

const option = interaction.customId.split(".")[1];

let memberDB = await fetchOrUpdateMember({ discord_id: interaction.user.id }, { }, { upsert: true });
if(memberDB.success == false) return await somethingWentWrong(interaction, true);
memberDB = memberDB.data;

let model = ai_models.filter(x => x.term === option)[0];
if(!model) return await somethingWentWrong(interaction, true);

const button = new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setLabel(`Get premium!`)
.setEmoji(`🎉`)
.setStyle(ButtonStyle.Link)
.setURL(links.patreon_page)
);

const componentsArray = [];
if(memberDB.ai_services.credits < model.credit_price) {
let embed = new EmbedBuilder()
.setTitle(`You have ran out of daily credits!`)
.setColor(settings.embed_colour)

if(!memberDB.isPremium) {
embed.addFields({ name: "Get more with premium!", value: `\`\`\`You can get an amount of 2,500 credits each day with premium! That's pretty much 100 generations instead of just 10!\`\`\`` })
componentsArray.push(button);
};

return interaction.editReply({ embeds: [ embed ], components: componentsArray, ephemeral: true }).catch(console.error);
}

const modal = new ModalBuilder()
.setCustomId(`aiGenerate.${model.term}`)
.setTitle(`Stable Diffusion (${model.term})`);

const prompt = new TextInputBuilder()
.setCustomId(`prompt`)
.setLabel(`Prompt`)
.setStyle(TextInputStyle.Paragraph);

const negative_prompts = new TextInputBuilder()
.setCustomId(`negative_prompt`)
.setLabel(`Negative Prompt`)
.setStyle(TextInputStyle.Paragraph)
.setRequired(false);

const firstActionRow = new ActionRowBuilder().addComponents(prompt);
const secondActionRow = new ActionRowBuilder().addComponents(negative_prompts);

modal.addComponents(firstActionRow, secondActionRow);
return interaction.showModal(modal);

}
const { ModalBuilder, TextInputBuilder, TextInputStyle, ActionRowBuilder, EmbedBuilder, ButtonStyle, ButtonBuilder } = require("discord.js");
const ai_models = require("../../../../settings/ai-models.json");
const { fetchOrUpdateMember } = require("../../../../functions/queryDB");
const settings = require("../../../../settings/clients/hentaicord.json");
const { somethingWentWrong } = require("../../../../functions/commonMessages");
const links = require("../../../../settings/links.json");

module.exports = async (interaction) => {

await interaction.deferReply().catch(console.error);

const option = interaction.customId.split(".")[1];

let memberDB = await fetchOrUpdateMember({ discord_id: interaction.user.id }, { }, { upsert: true });
if(memberDB.success == false) return await somethingWentWrong(interaction, true);
memberDB = memberDB.data;

let model = ai_models.filter(x => x.term === option)[0];
if(!model) return await somethingWentWrong(interaction, true);

const button = new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setLabel(`Get premium!`)
.setEmoji(`🎉`)
.setStyle(ButtonStyle.Link)
.setURL(links.patreon_page)
);

const componentsArray = [];
if(memberDB.ai_services.credits < model.credit_price) {
let embed = new EmbedBuilder()
.setTitle(`You have ran out of daily credits!`)
.setColor(settings.embed_colour)

if(!memberDB.isPremium) {
embed.addFields({ name: "Get more with premium!", value: `\`\`\`You can get an amount of 2,500 credits each day with premium! That's pretty much 100 generations instead of just 10!\`\`\`` })
componentsArray.push(button);
};

return interaction.editReply({ embeds: [ embed ], components: componentsArray, ephemeral: true }).catch(console.error);
}

const modal = new ModalBuilder()
.setCustomId(`aiGenerate.${model.term}`)
.setTitle(`Stable Diffusion (${model.term})`);

const prompt = new TextInputBuilder()
.setCustomId(`prompt`)
.setLabel(`Prompt`)
.setStyle(TextInputStyle.Paragraph);

const negative_prompts = new TextInputBuilder()
.setCustomId(`negative_prompt`)
.setLabel(`Negative Prompt`)
.setStyle(TextInputStyle.Paragraph)
.setRequired(false);

const firstActionRow = new ActionRowBuilder().addComponents(prompt);
const secondActionRow = new ActionRowBuilder().addComponents(negative_prompts);

modal.addComponents(firstActionRow, secondActionRow);
return interaction.showModal(modal);

}
ahh I had this error dont mind the text
AJ
AJ9mo ago
No description
AJ
AJ9mo ago
actually... i've not shown you the correct file.
AJ
AJ9mo ago
I'm not really sure how this error has came about.
AJ
AJ9mo ago
riight okay there's no way around this? sometimes my code might not complete before 3s How can I complete the checks before showing the modal tho? The checks would then come after the modal which is not what i was wanting I mean this error doesn't happen all the time, but it's something i'd like to just fix anyway pain, okay no worries thank you
Want results from more Discord servers?
Add your server