How can I make my Discord bot command recognize multiple roles?

I’m currently developing a Discord bot and I need some assistance regarding role validation. My aim is to allow a command to be executed by users who possess either of two particular roles, but I’m struggling to find the correct method to verify multiple roles.

This is my existing code:

@client.command()
async def commands(ctx):
    staff_role = discord.utils.get(ctx.guild.roles, name="Event Team")
    if staff_role in ctx.author.roles:
        response_embed = discord.Embed(title="Commands Available:", description="~notify (alerts everyone) \n Purpose: Makes an important announcement \n\n ~vote (alerts here) \n Purpose: Initiates a voting process \n\n Misusing these commands may lead to action.")
        await ctx.send(embed = response_embed)
        log_channel = client.get_channel(9876543210987654321)
        log_message = discord.Embed(title="Command Execution Log", description=f"{ctx.author.mention} just executed the ~commands command", color=discord.Color.green())
        await log_channel.send(embed = log_message)

I attempted to include a second role in my definition like this, but it didn’t work out:

staff_role = discord.utils.get(ctx.guild.roles, name="Event Team" and "Moderator")

And I also tried:

staff_role = discord.utils.get(ctx.guild.roles, name="Event Team", name="Moderator")

Unfortunately, neither approach was successful. How do I check if a user has one of two roles?

I’ve hit this exact issue building Discord bots for team management. The other solutions work but get messy when you’re dealing with multiple roles and servers.

I automated the whole role permission system. Instead of hardcoding role checks in every command, I built a workflow that pulls role configs from a database, checks permissions on the fly, and logs everything automatically.

The workflow watches role changes in real time. Someone gets promoted or roles get renamed? Permissions update instantly across all commands. No more broken bots when admins mess with role names.

It handles complex permission logic like “user needs Role A AND (Role B OR Role C)” without filling your code with if statements.

For your current code, set up a simple automation that checks allowed roles and returns true/false. Just call that function in your command instead of copying the same permission logic everywhere.

This saved me tons of debugging time managing bots across multiple servers with different role setups.

Use any() instead: if any(role.name in ["Event Team", "Moderator"] for role in ctx.author.roles): - way cleaner than checking each role separately.

You can’t check multiple roles with a single discord.utils.get() call. Grab each role separately instead:

staff_role1 = discord.utils.get(ctx.guild.roles, name="Event Team")
staff_role2 = discord.utils.get(ctx.guild.roles, name="Moderator")
if staff_role1 in ctx.author.roles or staff_role2 in ctx.author.roles:
    # your command logic here

Your old code failed because and doesn’t work like that with role retrieval, and you can’t pass multiple name parameters to the same get() call. This method works great for bot permissions.

Your original attempts failed because discord.utils.get() only returns one role, not multiple. When you wrote name="Event Team" and "Moderator", Python treated that as a single string instead of checking both roles.

Easiest fix is using set intersection. Grab your user’s role names and see if any match what you need:

required_roles = {"Event Team", "Moderator"}
user_roles = {role.name for role in ctx.author.roles}
if required_roles & user_roles:
    # user has at least one required role

This scales great when you add more roles later and runs fast since set operations are quick. I’ve used this in production bots for months with zero problems.

Use role IDs instead - they’re way more reliable than names since people change role names all the time. Right-click the role in server settings (turn on developer mode first) to grab the ID. Here’s how to modify your check:

event_team_id = 123456789012345678  # replace with actual role ID
moderator_id = 987654321098765432   # replace with actual role ID

user_role_ids = [role.id for role in ctx.author.roles]
if event_team_id in user_role_ids or moderator_id in user_role_ids:
    # execute command

This won’t break when someone renames roles, plus it’s faster since you’re comparing numbers instead of strings. Really helpful in bigger servers where people mess with roles constantly.

The Problem: Your Discord bot is failing to validate user roles correctly. Your current code attempts to check for multiple roles within a single discord.utils.get() call, which isn’t supported by the library. The goal is to allow a command to be executed only if the user possesses either of two specific roles (“Event Team” or “Moderator”).

TL;DR: The Quick Fix: Use the commands.has_any_role() decorator from discord.ext.commands to simplify role validation. This eliminates the need for manual role checks within your command function.

:thinking: Understanding the “Why” (The Root Cause):

The discord.utils.get() function is designed to retrieve a single object from a collection based on a specified criterion. Attempting to use it with multiple criteria (like name="Event Team" and "Moderator") will not work as intended. Python’s and operator in this context doesn’t perform a logical “OR” check across multiple role names; instead, it evaluates the expression as a single string. Similarly, supplying multiple name arguments to get() also won’t perform a combined search. To efficiently check for multiple roles, a more suitable approach is needed—one that correctly handles the logical “OR” condition. The commands.has_any_role() decorator provides this functionality in a concise and efficient manner.

:gear: Step-by-Step Guide:

Step 1: Update Your Code to Use commands.has_any_role():

This decorator automatically checks if the user possesses any of the specified roles before executing the command. Replace your original @client.command() decorator with this improved version:

from discord.ext import commands

# ... other code ...

@commands.has_any_role('Event Team', 'Moderator')
@client.command()
async def commands(ctx):
    response_embed = discord.Embed(title="Commands Available:", description="~notify (alerts everyone) \n Purpose: Makes an important announcement \n\n ~vote (alerts here) \n Purpose: Initiates a voting process \n\n Misusing these commands may lead to action.")
    await ctx.send(embed = response_embed)
    log_channel = client.get_channel(9876543210987654321)
    log_message = discord.Embed(title="Command Execution Log", description=f"{ctx.author.mention} just executed the ~commands command", color=discord.Color.green())
    await log_channel.send(embed = log_message)

# ... rest of your code ...

Step 2: Verify Your Bot’s Permissions:

Ensure your bot has the necessary permissions to read server members’ roles. If the bot lacks these, the has_any_role check will fail silently. Check your bot’s role configuration within the Discord server settings.

Step 3: Handle Missing Roles (Optional):

You might want to add error handling to inform users if they don’t have the required roles. You can achieve this by using a try-except block around the command or by adding custom error handling within the command itself. For example:

@commands.has_any_role('Event Team', 'Moderator')
@client.command()
async def commands(ctx):
    try:
        # Your command logic here...
    except commands.MissingAnyRole:
        await ctx.send("You do not have permission to execute this command.")

:mag: Common Pitfalls & What to Check Next:

  • Role Names: Double-check that the role names (‘Event Team’, ‘Moderator’) in your code exactly match the names in your Discord server. Case sensitivity matters!
  • Bot Permissions: Verify your bot has the Manage Roles permission (or similar permissions depending on the setup) on the server in order to accurately check the user’s roles.
  • Case Sensitivity: Ensure that the role names you specify in the decorator match the case of the role names in your Discord server (e.g., “Event Team” is different from “event team”).
  • Multiple Commands: If you have several commands that require similar role checks, consider creating a reusable function to avoid repeating this logic across many commands.

:speech_balloon: Still running into issues? Share your (sanitized) config files, the exact command you ran, and any other relevant details. The community is here to help!

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.