What's the best way to extract user IDs from mentions in a Discord bot command?

I’m working on a Discord bot that shows user profile information. When users run !userinfo @someone, I need to get the actual user ID from the mention to search my database.

command_text = str(message.content[9:])
clean_id = re.sub("[!@#$%^&*()[]{};:,./<>?\|`~-=_+]", " ", command_text)
print(clean_id)

The problem is that Discord mentions come in the format <@123456789012345678> but my regex isn’t cleaning it properly. I still get weird formatting instead of just the numeric ID I need for database queries. There must be a cleaner approach to handle user mentions in Discord bot commands. Any suggestions?

I hit this same problem building my moderation bot last year. Skip manual parsing - use discord.py’s converter system instead. Way cleaner.

Set up your command to auto-convert mentions to User objects:

@bot.command()
async def userinfo(ctx, user: discord.User = None):
    if user is None:
        user = ctx.author
    user_id = user.id
    # Now you have the clean integer ID for database lookup

This handles everything automatically - regular mentions, nickname mentions, even raw user IDs. Built-in error handling too when someone drops an invalid mention. Way more reliable than string manipulation and won’t break with Discord updates.

yeh, fr, just do message.mentions[0].id. way easier than regex, plus u get the full user obj with name and avatar. no need for extra api calls.

The Problem: Your Discord bot is failing to extract the user ID from Discord mentions in the format <@123456789012345678>. Your current regular expression approach is not effectively cleaning the mention string, leaving you with unwanted formatting instead of just the numeric ID needed for database queries.

TL;DR: The Quick Fix: Use string manipulation to directly extract the user ID from the mention string, handling both regular and nickname mentions.

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

Your regular expression re.sub("[!@#$%^&*()[]{};:,./<>?\|~-=_+]", " ", command_text)replaces special characters with spaces, but it doesn't remove the<@>characters or the potential!` for nickname mentions. This leaves you with a string containing spaces and other characters that prevent you from directly converting to an integer. A more efficient approach is to directly parse the string using string slicing and conditional checks.

:gear: Step-by-Step Guide:

Step 1: Extract the Mention:

First, extract the mention from the message content. Assume the command is always at the beginning of the message:

if message.content.startswith('!userinfo'):
    mention = message.content.split()[1] #Extracts the second word from the message.

Step 2: Clean and Convert to Integer:

Now clean the mention string, removing the <@> and optional !:

    if mention.startswith('<@') and mention.endswith('>'):
        user_id = mention[2:-1] #Removes <@ and >
        if user_id.startswith('!'):
            user_id = user_id[1:] #Removes ! if present (nickname mention)
        try:
            user_id = int(user_id) #Convert to an integer.  Will throw ValueError if not a valid number.
            # Now user_id contains the clean integer user ID.
            # Proceed with your database query using this user_id.
        except ValueError:
            print("Invalid user ID in mention.")
            # Handle the error appropriately (e.g., send an error message to the user).

Step 3: Handle Errors:

The try-except block handles potential ValueError exceptions if the mention does not contain a valid number. It’s crucial to handle this to prevent crashes. You might want to inform the user that the mention was invalid.

Step 4: Database Query:

Finally, use the extracted user_id in your database query. Make sure your database query is properly parameterized to prevent SQL injection vulnerabilities:

    #Example using a parameterized query (adapt to your specific database library)
    cursor.execute("SELECT * FROM users WHERE user_id = %s", (user_id,)) 
    # ...rest of your database code...

:mag: Common Pitfalls & What to Check Next:

  • Multiple Mentions: The code above assumes only one mention. If a user can mention multiple people, you will need to adapt the code to handle multiple mentions. Consider using message.mentions if your Discord.py version supports it.

  • Invalid Mentions: Users might enter invalid mentions. Always validate the extracted ID before attempting database queries to prevent errors.

  • Case Sensitivity: Ensure your database query handles case sensitivity appropriately (depending on your database setup and column definitions).

  • Error Handling: Add more robust error handling, such as logging errors to a file for debugging and sending informative error messages to the user if the mention is invalid or the user isn’t found in the database.

: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!

Try using discord.py’s discord.utils.get() with message processing. I’ve had good luck with this for edge cases other methods miss.

import discord
from discord.utils import get

# Extract ID from mention string
mention_text = message.content.split()[1]
if '<@' in mention_text:
    raw_id = mention_text.strip('<@!>')
    user = get(bot.get_all_members(), id=int(raw_id))
    if user:
        user_id = user.id

Gives you better error handling than converters and it’s more reliable than just string manipulation. Plus it checks if the user actually exists in your bot’s scope before you hit the database.

Been dealing with this exact issue for months in production. Most solutions here fail because they don’t handle server members who’ve left but still get mentioned in chat history. Your regex breaks because Discord encodes mentions differently than what you see in the UI.

What actually works is combining mention extraction with guild member validation:

if message.mentions:
    target_user = message.mentions[0]
    user_id = target_user.id
else:
    # Fallback for edge cases
    mention_match = re.search(r'<@!?(\d+)>', message.content)
    if mention_match:
        user_id = int(mention_match.group(1))

This handles 90% of cases with built-in parsing and has regex backup for weird formatting. Use proper capture groups instead of replacing characters. You’ll get clean integer extraction without breaking on nickname mentions or deleted users.

just strip the angle brackets and @ symbol manually. user_id = mention.replace('<@', '').replace('>', '').replace('!', '') works fine for most cases. it’s a bit hacky compared to other solutions here, but it gets the job done.

All these approaches work, but you’re still writing custom parsing logic or getting locked into discord.py specifics. What happens when you need mentions on other platforms?

I just use Latenode to automate everything. Set up a webhook for Discord messages, extract user IDs with string manipulation, query your database, and send the response back.

Best part? The same user lookup works for Slack, Teams, whatever. You get error handling built-in and can easily add caching or logging.

10 minutes to set up the workflow, then you’re done. No more hardcoded mention parsing in your bot.

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