Error with automatic role assignment in Discord bot - on_member_join issue

I’m facing some issues with my Discord bot that’s supposed to automatically assign roles to new users when they join. I’m still learning Python, and I think I might be overlooking something.

The role setup command works perfectly when I test it, but as soon as a new member joins the server, I see this error in my console:

Ignoring exception in on_member_join
Traceback (most recent call last):
  File "discord/client.py", line 307, in _run_event
    yield from getattr(self, event)(*args, **kwargs)
  File "bot.py", line 28, in on_member_join
    await bot.assign_role(user, target_role)
AttributeError: 'discord.client.Client' object has no attribute 'assign_role'

Here’s the code for my main bot file:

import discord
from discord.ext import commands

import config
from modules import role_manager

bot = discord.Client()

bot_commands = dict(setrole=role_manager)

@bot.event
async def on_ready():
    print("Bot is up and running!")
    await bot.change_presence(activity=discord.Game(name="managing roles"))

@bot.event
async def on_message(msg):
    if msg.content.startswith(config.COMMAND_PREFIX):
        command = msg.content[len(config.COMMAND_PREFIX):].split(" ")[0]
        parameters = msg.content.split(" ")[1:]
        if command in bot_commands:
            await bot_commands.get(command).execute(parameters, msg, bot, command)
        else:
            error_embed = discord.Embed(color=discord.Color.red(), description=f"Command `{command}` not found!")
            await bot.send_message(msg.channel, embed=error_embed)

@bot.event
async def on_member_join(user):
    target_role = role_manager.fetch_role(user.server)
    if target_role is not None:
        await bot.assign_role(user, target_role)

bot.run(config.BOT_TOKEN)

And here’s how my role manager module looks:

import os
from os import path
import discord

async def send_error(message, channel, bot_client):
    error_embed = discord.Embed(color=discord.Color.red(), description=message)
    await bot_client.send_message(channel, embed=error_embed)

async def fetch_role(guild):
    file_path = f"DATA/{guild.id}/role_config"
    if path.exists(file_path):
        with open(file_path, 'r') as file:
            role_id = file.read()
            return discord.utils.get(guild.roles, id=role_id)
    return None

async def save_config(role_id, guild):
    directory = f"DATA/{guild.id}"
    if not path.exists(directory):
        os.makedirs(directory)
    with open(f"{directory}/role_config", "w") as config_file:
        config_file.write(role_id)

async def execute(params, message, bot_client, command_name):
    if len(params) > 0:
        role_name = ' '.join(params)
        found_role = discord.utils.get(message.server.roles, name=role_name)
        if found_role is None:
            await send_error("That role doesn't exist on this server!", message.channel, bot_client)
        else:
            try:
                await save_config(found_role.id, message.server)
                success_embed = discord.Embed(color=discord.Color.green(), description=f"Auto-role set to `{found_role.name}`!")
                await bot_client.send_message(message.channel, embed=success_embed)
            except Exception as e:
                await send_error("Failed to save role configuration!", message.channel, bot_client)

What could be causing this issue? The error indicates that assign_role isn’t a valid method, but I’m unsure of what I should be using instead.

Your problem is using discord.Client() instead of commands.Bot() - Client doesn’t have assign_role. Since you’re already importing commands, just change it to bot = commands.Bot(command_prefix=config.COMMAND_PREFIX) at the top. This gives you all the role management methods you need. Then in on_member_join, use await user.add_roles(target_role) instead of assign_role (which doesn’t exist). I made the same mistake when I started - Client is pretty bare-bones compared to Bot. Also, make sure your fetch_role function converts role_id back to an integer when reading from the file, since discord.utils.get needs an int for the id parameter.

You’re using outdated discord.py methods. Your code looks like it’s written for an older version but you’re running a newer one. Mike71 already mentioned the assign_role issue, but there’s more stuff that needs fixing. Change bot.send_message(msg.channel, embed=error_embed) to await msg.channel.send(embed=error_embed), and swap message.server for message.guild in your role_manager module. For the role ID in your config file, save it as a string with str(found_role.id) then convert back to int with int(role_id) when reading - discord.utils.get needs an integer for the id parameter. I ran into the same problems migrating my bot and these fixes sorted it out.

you’re mixing old discord.py syntax with newer versions. assign_role doesn’t exist anymore - use user.add_roles(target_role) instead in your on_member_join function. also, user.server should be user.guild in newer versions.