Skip to content

Unreaction event not caught after restart  #10487

Open
@eirikhanasand

Description

Which package is this bug report for?

discord.js

Issue description

When I react to a message then restart the bot then unreact it doesnt catch the unreaction event.

// Process existing reactions
            for (const [_, reaction] of roleMessage.reactions.cache) {
                const users = await reaction.users.fetch();
                users.forEach(async (user: User) => {
                    if (user.bot) return;

                    try {
                        const member = await guild.members.fetch(user.id);

                        const emoji = reaction._emoji.name;
                        const reactionText = emoji.length < 4 ? emoji.slice(0, 2) : emoji;

                        for (let i = 0; i < icons.length; i++) {
                            if (icons[i].trim() === reactionText.trim()) {
                                await member.roles.add(roleIds[i]);
                                break;
                            }
                        }
                    } catch (error: any) {
                        if (error.code === 10007) {
                            // Member not found (likely left the guild)
                        } else {
                            console.error("Error fetching member or adding role:", error);
                        }
                    }
                });
            }

if I log reactionText it logs my reaction successfully after the restart. If I then wait for

console.log("Finished processing existing reactions.");

then unreact, the following function doesnt catch it:

roleCollector.on('remove', async (clickedReaction: Reaction, user: User) => {
                const member = await guild.members.fetch(user.id);
                const emoji = clickedReaction._emoji.name;
                const reaction = emoji.length < 4 ? emoji.slice(0, 2) : emoji;

                for (let i = 0; i < icons.length; i++) {
                    if (icons[i].trim() === reaction.trim()) {
                        await member.roles.remove(roleIds[i]);
                        break;
                    }
                }
            });

However if I unreact then re-react then unreact again, the above function does catch the 2nd unreaction.

Code sample

client.once(Events.ClientReady, async () => {
    console.log("roles:", roles);
    for (const role of roles) {
        try {
            const { message, channelID } = role;

            // Fetch channel and message
            const channel = await client.channels.fetch(channelID);
            if (!channel) return console.log(`Channel with ID ${channelID} not found.`);
            const roleMessage = await (channel as any).messages.fetch(message);
            if (!roleMessage) return console.log(`Message with ID ${message} not found.`);

            // Extract guild, roles, and icons
            const guild = client.guilds.cache.get(roleMessage.guildId);
            const content = roleMessage.embeds[0].data.fields[0].value;
            if (!guild) return console.log(`Guild ${roleMessage.guildId} does not exist.`);

            const roleRegex = /<@&(\d+)>/g;
            const messageRoles = content.match(roleRegex) || [];
            const roleIds = messageRoles.map((match: string) => match.slice(3, -1));

            const icons = content.split('\n').map((icon: string) =>
                icon[1] === ':' ? icon.split(':')[1] : icon.substring(0, 2)
            );

            // Process existing reactions
            for (const [_, reaction] of roleMessage.reactions.cache) {
                const users = await reaction.users.fetch();
                users.forEach(async (user: User) => {
                    if (user.bot) return;

                    try {
                        const member = await guild.members.fetch(user.id);

                        const emoji = reaction._emoji.name;
                        const reactionText = emoji.length < 4 ? emoji.slice(0, 2) : emoji;

                        for (let i = 0; i < icons.length; i++) {
                            if (icons[i].trim() === reactionText.trim()) {
                                await member.roles.add(roleIds[i]);
                                break;
                            }
                        }
                    } catch (error: any) {
                        if (error.code === 10007) {
                            // Member not found (likely left the guild)
                        } else {
                            console.error("Error fetching member or adding role:", error);
                        }
                    }
                });
            }

            console.log("Finished processing existing reactions.");

            // Create a reaction collector
            const roleCollector = roleMessage.createReactionCollector({
                filter: (reaction: Reaction, user: User) => !user.bot,
                dispose: true,
            });

            roleCollector.on('collect', async (clickedReaction: Reaction, user: User) => {
                const member = await guild.members.fetch(user.id);
                const emoji = clickedReaction._emoji.name;
                const reaction = emoji.length < 4 ? emoji.slice(0, 2) : emoji;

                for (let i = 0; i < icons.length; i++) {
                    if (icons[i].trim() === reaction.trim()) {
                        await member.roles.add(roleIds[i]);
                        break;
                    }
                }
            });

            roleCollector.on('remove', async (clickedReaction: Reaction, user: User) => {
                const member = await guild.members.fetch(user.id);
                const emoji = clickedReaction._emoji.name;
                const reaction = emoji.length < 4 ? emoji.slice(0, 2) : emoji;

                for (let i = 0; i < icons.length; i++) {
                    if (icons[i].trim() === reaction.trim()) {
                        await member.roles.remove(roleIds[i]);
                        break;
                    }
                }
            });
        } catch (error: any) {
            console.error("Error processing roles:", error);
        }
    }

    console.log("Ready!");
});

Versions

Discord: discord.js@14.16.1
Node: v22.7.0
Typescript: typescript@5.4.5
MacOS: 14.3.1 (23D60)

Issue priority

Medium (should be fixed soon)

Which partials do you have configured?

Message, Channel, User, Reaction

Which gateway intents are you subscribing to?

Guilds, GuildModeration, GuildMessages, GuildMessageReactions, MessageContent

I have tested this issue on a development release

No response

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions