Discord.py bot role assignment broken after updating from v1.7.3 to v2.3.2

I just upgraded my Discord bot from discord.py version 1.7.3 to 2.3.2 and now my role assignment feature stopped working completely. I tried fixing it by adding discord.Intents.all() and setting intents.message_content = True but nothing changed. I’m pretty new to this so I’m not sure what went wrong.

Here’s my code:

import discord
from discord.ext import commands
from decouple import config

intents = discord.Intents.default()
intents.members = True
client = commands.Bot("?", intents=intents)

class RoleManager(commands.Cog):
    def __init__(self, client):
        self.client = client

    @commands.Cog.listener()
    async def on_raw_reaction_add(self, reaction_payload):
        msg_id = reaction_payload.message_id
        
        server_id = reaction_payload.guild_id
        react_emoji = reaction_payload.emoji
        
        server = self.client.get_guild(server_id)
        user = server.get_member(reaction_payload.user_id)
        
        elif msg_id == FIRST_MESSAGE_ID:
            target_role = None
            if str(react_emoji) == "👥":
                target_role = server.get_role(ROLE_ID_HERE)
            elif str(react_emoji) == "📢":
                target_role = server.get_role(ROLE_ID_HERE)
            elif str(react_emoji) == "📖":
                target_role = server.get_role(ROLE_ID_HERE)
            if target_role is not None:
                await user.add_roles(target_role)
                
        elif msg_id == SECOND_MESSAGE_ID:
            target_role = None
            if str(react_emoji) == "🎮":
                target_role = server.get_role(ROLE_ID_HERE)
            elif str(react_emoji) == "💻":
                target_role = server.get_role(ROLE_ID_HERE)
            elif str(react_emoji) == "🎨":
                target_role = server.get_role(ROLE_ID_HERE)
            if target_role is not None:
                await user.add_roles(target_role)

client.add_cog(RoleManager(client))

TOKEN = config("TOKEN")
client.run(TOKEN)

I expected the intents changes would fix any compatibility issues between the old and new discord.py versions but the bot still doesn’t assign roles when people react to messages. What am I missing here?

check your bot’s permissions in the server - v2 migration can mess up role hierarchy. make sure your bot’s role is above any roles it’s trying to assign, otherwise it’ll just fail without throwing errors.

This isn’t just about syntax errors and cog loading. Discord.py v2 broke how reaction events work. Your on_raw_reaction_add listener probably isn’t firing because of permission scope changes.

I hit this same issue last year during my upgrade. Even with proper intents in the developer portal, my bot kept missing reaction events. Fixed it by adding explicit guild permission checks and making sure the bot could actually see the messages it was monitoring.

Toss this debug line at the start of your listener to see if events are even firing: print(f"Reaction detected: {reaction_payload.emoji} on message {reaction_payload.message_id}")

Also check if your message IDs are still valid after migrating. Version updates sometimes corrupt those constants. Grab fresh message IDs and test again.

Had the same problem when I moved to discord.py v2. That syntax error’s one thing, but you also need to completely change how you load cogs. The old add_cog() method doesn’t work anymore.

Ditch this:

client.add_cog(RoleManager(client))

Use this instead:

async def setup():
    await client.add_cog(RoleManager(client))

asyncio.run(setup())

Double-check your bot has “Manage Roles” permission in server settings too. I wasted hours debugging until I realized the migration reset my bot permissions. Your intents look fine - just fix the cog loading and syntax stuff.

Yeah, everyone’s talking about syntax errors, but that’s not your main problem. Discord.py v2 completely changed how bot startup works - you can’t run synchronous cog loading in an async environment anymore. I hit this same wall when I migrated to v2. You need to put your bot initialization inside an async main function now. That old trick of just calling client.run() at the bottom? Doesn’t work with cog loading anymore. Wrap everything in an async main function and use await client.start() instead. Also, if you’re planning slash commands later, make sure you handle the new application command tree - v2 requires it for most bot stuff. The permission issues people mentioned are real too, but fix your initialization sequence first. Then go back and add that missing if statement before your elif block.

Yeah, there’s a syntax error, but the bigger issue is you’re missing the bot permissions setup that changed in v2. Discord.py v2 needs you to register privileged gateway intents in your Discord Developer Portal.

Hit up your bot settings and turn on “Server Members Intent” under Privileged Gateway Intents. Your code has intents.members = True but it’s useless unless you flip that switch in the portal.

Also fix that missing if before your elif msg_id == FIRST_MESSAGE_ID: line.

Honestly, Discord bots are a pain with all these version changes and permission headaches. I’d just automate your role management through Latenode instead. You can build the same reaction-role system without discord.py breaking on you.

Latenode handles Discord API stuff cleanly and you set up everything visually. Way easier to maintain.

I’ve hit this migration nightmare multiple times. Yeah, there’s that syntax error everyone mentioned, but discord.py v2 also changed how message caching works.

Your bot can’t see the original messages anymore because v2 has stricter cache limits. When on_raw_reaction_add fires, it’s probably getting None values for messages that worked fine in v1.7.3.

Try this after getting your server object:

channel = server.get_channel(reaction_payload.channel_id)
message = await channel.fetch_message(msg_id)

Honestly though, maintaining Discord bots through these API changes is exhausting. Every major update breaks something new.

I switched my role management to Latenode because it handles all the Discord API complexity. You can build reaction role systems without any discord.py code - just drag and drop the logic.

When Discord pushes breaking changes, Latenode updates their Discord nodes automatically. No more migration headaches.

you’re missing an if statement before that elif - that’s what’s causing the syntax error. also, switch to await client.load_extension() instead of add_cog() since v2 changed how cogs work.