Modal submission issues with Discord bot
I’ve got a Discord bot built with discord.js that uses several modals triggered by buttons in embedded messages. Everything was working perfectly for about a month.
Now all the modals are broken. When users try to submit any modal, they get the generic “Something went wrong. Try again.” error message. I haven’t changed any code recently. I even tried running the bot on a completely different server but the same problem happens.
The weird part is that the bot responds to everything else normally. The error shows up really fast (under 2 seconds). I have console logs that fire when the modal opens and when someone hits Submit. The problem is my server only sees the first log - it’s like the submit action never reaches my code.
Here’s the main interaction handler:
export async function handleInteraction(
botClient: CustomClient,
userInteraction: Interaction,
rewardContract: TokenDistribution,
taskQueue: ProcessingQueue
): Promise<void> {
const getTimestamp = (): string => new Date(Date.now()).toUTCString();
const logChannel = botClient.channels.cache.get(channels.logs) as TextChannel;
try {
console.log("Interaction received");
// Verify user isn't rate limited
const allowedToProceed = await validateUserCooldown(userInteraction.user.id);
if (!allowedToProceed) {
if (userInteraction.isRepliable()) {
await userInteraction.reply({
content: "Please wait before trying again. You're doing that too fast.",
ephemeral: true,
});
}
return;
}
// Handle slash commands
if (userInteraction.isChatInputCommand()) {
await userInteraction.deferReply({ ephemeral: true });
if (userInteraction.commandName === "rewards") {
await showMainInterface(userInteraction, rewardContract);
} else {
await userInteraction.editReply({
content: "Unknown command detected!",
});
await logChannel.send(
`[WARNING]\n${getTimestamp()}\nUnknown Command\nUser: ${
userInteraction.user.username
}`
);
}
} else if (userInteraction.isButton()) {
// Handle button clicks
if (userInteraction.customId === "search_wallet") {
await processWalletSearch(userInteraction, rewardContract);
} else if (userInteraction.customId === "configure_network") {
await handleNetworkConfig(userInteraction, rewardContract, taskQueue);
} else if (userInteraction.customId === "update_username") {
await processUsernameUpdate(userInteraction, rewardContract, taskQueue);
} else if (userInteraction.customId === "reset_results") {
await userInteraction.deferUpdate();
await clearUserResults(userInteraction, rewardContract);
} else if (userInteraction.customId === "start_process") {
await userInteraction.deferReply({ ephemeral: true });
await initiateClaimProcess(userInteraction, rewardContract, taskQueue);
} else {
await userInteraction.reply({
content: "This button isn't working right now!",
ephemeral: true,
});
await logChannel.send(
`[WARNING]\n${getTimestamp()}\nUnknown Button\nUser: ${
userInteraction.user.username
}`
);
}
} else if (userInteraction.isModalSubmit()) {
// Handle modal submissions
await userInteraction.deferReply({ ephemeral: true });
if (userInteraction.customId === "network_config_form") {
await handleNetworkConfig(userInteraction, rewardContract, taskQueue);
} else if (userInteraction.customId === "address_input_form") {
await processWalletSearch(userInteraction, rewardContract);
} else if (userInteraction.customId === "username_update_form") {
await processUsernameUpdate(userInteraction, rewardContract, taskQueue);
} else {
await userInteraction.editReply({
content: "This form isn't configured properly!",
});
await logChannel.send(
`[WARNING]\n${getTimestamp()}\nUnknown Modal\nUser: ${
userInteraction.user.username
}`
);
}
} else {
await logChannel.send(
`[WARNING]\n${getTimestamp()}\nUnknown Interaction\nUser: ${
userInteraction.user.username
}`
);
}
} catch (err) {
console.error(`Interaction Error: ${err}`);
await logChannel.send(`[ERROR]\n${getTimestamp()}\nInteraction Failed\n${err}`);
if (userInteraction.isRepliable()) {
await userInteraction.editReply({
content: `Error occurred: ${err.message}`,
});
}
}
}
And here’s the function that handles the wallet search:
export async function processWalletSearch(
userInteraction: ModalSubmitInteraction | ButtonInteraction,
rewardContract: TokenDistribution
): Promise<void> {
if (userInteraction.isButton()) {
try {
console.log(
"Wallet search button clicked by " +
userInteraction.user.username +
" - " +
userInteraction.user.id
);
const inputForm = await buildWalletInputModal();
await userInteraction.showModal(inputForm);
await userInteraction.deleteReply();
} catch (err) {
console.log(err);
}
} else if (userInteraction.isModalSubmit()) {
const currentUserId = userInteraction.user.id;
console.log(
"Wallet search form submitted by " + userInteraction.user.username + " - " + currentUserId
);
// ... rest of processing
}
}
Anyone else run into this? I’m completely stuck on what could cause modals to just stop working like this.