Open
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