How do I properly manage a modal?

I'm attempting to get a modal working and I have my flow setup like this. - Slash command /debug - Create Custom Modal - Create Filter - interaction.showModal(...) - interaction.awaitModalSubmit(...) - modalInteraction.reply My code is as follows.
const modal = new BeginQuestModal('Begin Quest', ['Name', 'Description']);
const filter = (i: ModalSubmitInteraction) => i.customId === modal.customId;

await interaction.showModal(modal);

try {
const modalInteraction = await interaction.awaitModalSubmit({ time: 15_000, filter });
const values = modalInteraction.fields.fields;
console.log(values);

// First reply to the modal interaction
await modalInteraction.reply({
content: `Modal submitted:\n${values.map(v => `${v.customId}: ${v.value}`).join('\n')}`,
flags: MessageFlags.Ephemeral
});
} catch (e) {
console.error(e);
// Only try to reply if the interaction hasn't been replied to yet
if (!interaction.replied && !interaction.deferred) {
await interaction.reply({
embeds: [new ErrorEmbed('Modal Error', 'The modal timed out or encountered an error.')],
flags: MessageFlags.Ephemeral
});
}
}
const modal = new BeginQuestModal('Begin Quest', ['Name', 'Description']);
const filter = (i: ModalSubmitInteraction) => i.customId === modal.customId;

await interaction.showModal(modal);

try {
const modalInteraction = await interaction.awaitModalSubmit({ time: 15_000, filter });
const values = modalInteraction.fields.fields;
console.log(values);

// First reply to the modal interaction
await modalInteraction.reply({
content: `Modal submitted:\n${values.map(v => `${v.customId}: ${v.value}`).join('\n')}`,
flags: MessageFlags.Ephemeral
});
} catch (e) {
console.error(e);
// Only try to reply if the interaction hasn't been replied to yet
if (!interaction.replied && !interaction.deferred) {
await interaction.reply({
embeds: [new ErrorEmbed('Modal Error', 'The modal timed out or encountered an error.')],
flags: MessageFlags.Ephemeral
});
}
}
Something is "Off" about this as I consistently get errors such as: - Unknown Interaction - Collector received no interactions before ending with reason: time - The reply to this interactions has not been sent or deferred Which suggests to me that I honestly have no idea what is required to properly show a modal, and get its reply back with the data. Is there a standard way of prompting for a modal input and getting the responses back? NOTE This is showing the modal, and I am getting the data back, but the catch block is always being thrown with those errors. The bot is not crashing.
15 Replies
d.js toolkit
d.js toolkit2d 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! - Marked as resolved by OP
Amgelo
Amgelo2d ago
are you sure modal.customId isn't undefined?
duck
duck2d ago
Collector received no interactions before ending with reason: time
I hope this one is self explanatory, but in case it isn't, it just means that your collector timed out unless it's specifically by design, I'd personally consider 15 seconds to be a little short
The reply to this interactions has not been sent or deferred
in the above code, you aren't actually calling any methods that could throw this error, so I have to assume some other code is also attempting to handle the same interaction this could also explain Unknown Interaction
d.js docs
d.js docs2d 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
xTwisteDx
xTwisteDxOP2d ago
Here's the modal that I'm constructing, the ID does exist, and it's the same else it'd never pass the filter.
export class BeginQuestModal extends ModalBuilder {
public customId: string;

constructor(title: string, inputFields: string[]) {
super();

this.customId = `modal:beginQuest:${randomUUID()}`;
this.setCustomId(this.customId)
.setTitle(title);

const textInputComponents: TextInputBuilder[] = [];
for (const field of inputFields) {
textInputComponents.push(
new TextInputBuilder()
.setCustomId(field)
.setLabel(field)
.setStyle(TextInputStyle.Short)
.setRequired(true)
);
}

for (const component of textInputComponents) {
const actionRow = new ActionRowBuilder<TextInputBuilder>().addComponents(component);
this.addComponents(actionRow);
}
}
}
export class BeginQuestModal extends ModalBuilder {
public customId: string;

constructor(title: string, inputFields: string[]) {
super();

this.customId = `modal:beginQuest:${randomUUID()}`;
this.setCustomId(this.customId)
.setTitle(title);

const textInputComponents: TextInputBuilder[] = [];
for (const field of inputFields) {
textInputComponents.push(
new TextInputBuilder()
.setCustomId(field)
.setLabel(field)
.setStyle(TextInputStyle.Short)
.setRequired(true)
);
}

for (const component of textInputComponents) {
const actionRow = new ActionRowBuilder<TextInputBuilder>().addComponents(component);
this.addComponents(actionRow);
}
}
}
I think somehow it was my cache... seems to have cleared up after cleaning my environment... weird.
Amgelo
Amgelo2d ago
did you setup sweepers or limits?
xTwisteDx
xTwisteDxOP2d ago
What do you mean by sweepers?
Amgelo
Amgelo2d ago
probably not then
xTwisteDx
xTwisteDxOP2d ago
Are you referring to an event handler that catches all chat interaction events?
Amgelo
Amgelo2d ago
no, a cache sweeper
xTwisteDx
xTwisteDxOP2d ago
I have one for my deploy script, but it doesn't do it on build.
Amgelo
Amgelo2d ago
they're specifically called sweepers in the client options so if you don't know what they are, you didn't setup one those two are the only thing that can mess up cache unless you do .cache.clear() somewhere ig
xTwisteDx
xTwisteDxOP2d ago
I was referring to cache as my transpiled dist code. So not the same thing lol
Amgelo
Amgelo2d ago
that's not cache at all
xTwisteDx
xTwisteDxOP2d ago
Hindsight is 20/20. Terminology is hard even after 6+ years of doing this stuff xD

Did you find this page helpful?