Search code examples
typescriptdiscorddiscord.js

The reply to this interaction has not been sent or deferred, but only sometimes


I'm using TypeScript to write my Discord bot, and its main purpose is sending cute axolotl pictures.

It uses a REST API to do this, but it's on free hosting so it can be quite slow sometimes, especially when it hasn't been used in a while. So to prevent the same issue Nextcord (discord.py fork) - How can I return to Discord that a command is currently running? had, I'm deferring the reply. However, this only seems to work sometimes, other times it crashes the code because it's trying to edit a non-deferred reply?

Relevant part of ImageCommand.ts:

export default (client: Client, commandsArray: Array<CommandInterface>) => {
    commandsArray.push({
        name: "image",
        description: "Sends you a cute axolotl picture from Reddit.",
        executor: async (interaction: ChatInputCommandInteraction, client: Client) => {
            interaction.deferReply();

            const channel: TextChannel = interaction.channel as TextChannel;

            let payload = "?minImages=1&flair=Just Showing Off 😍";
            if (channel.nsfw) payload += "&nsfw=1"; // If for some reason a cute axolotl picture is marked as NSFW, only show it when sent from a NSFW channel

            const post = (await Axios.get("https://axolotlapi.kirondevcoder.repl.co/reddit" + payload)).data.data[0];
            
            const images: Array<ImageInterface> = post.media.filter((m: any) => m.kind === "image");
            const image: string = images[Math.floor(Math.random() * images.length)].url;

            const embed = new EmbedBuilder()
                .setTitle(post.title)
                .setAuthor({ name: `u/${post.author}`, url: `https://reddit.com/u/${post.author}` })
                .setURL(post.link)
                .setTimestamp(post.created_utc * 1000)
                .setImage(image)
            ;

            interaction.editReply({ embeds: [ embed ]});
        }
    });
}

I tried deferring the reply like in Nextcord (discord.py fork) - How can I return to Discord that a command is currently running?, but that only works sometimes. When it does not work, it just crashes the code.


Solution

  • <ChatInputCommandInteraction>#deferReply returns a promise which you are not awaiting.

    Change

    interaction.deferReply();
    

    to

    await interaction.deferReply();
    

    It is also worth noting the type for the interaction should be ChatInputCommandInteraction<"cached"> not just ChatInputCommandInteraction since the interaction is already cached. (source)

    documentation