You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Discord.py反应角色机器人报'NoneType'无'roles'属性错误如何解决

错误原因定位

报错AttributeError("'NoneType' object has no attribute 'roles'")指向member.roles调用,说明你通过utils.get(message.guild.members, id=payload.user_id)拿到的member对象是None。
这个问题是Discord.py版本迭代导致的,一年前你使用的大概率是v1.x版本,v2.x版本之后做了两个核心调整导致原有代码失效:

  • 默认关闭服务器成员缓存,message.guild.members只能拿到当前已缓存的少量成员,大部分用户查询都会返回None
  • 强制要求明确声明网关意图,成员相关的接口需要手动开启权限才能调用
修复步骤
  1. 开启开发者后台权限
    进入Discord开发者平台对应Bot的管理页,找到「Privileged Gateway Intents」板块,开启Server Members Intent权限。
  2. 代码中添加意图声明
    初始化Client的时候明确指定需要的意图,开启成员访问权限。
  3. 替换成员获取方式
    不要用缓存查询的utils.get获取成员,改用直接请求API的fetch_member方法,避免缓存缺失导致返回None。
  4. 增加非空校验逻辑
    拿到成员对象后先判断是否为None,避免后续调用属性报错。
修改后的完整代码
import discord
from discord import utils
import config

# 声明需要的网关意图
intents = discord.Intents.default()
intents.members = True # 开启成员访问意图
intents.guilds = True
intents.message_content = True # 可根据实际需求调整

class MyClient(discord.Client):

    async def on_ready(self):
        print('Logged on as {0}!'.format(self.user))
    async def on_raw_reaction_add(self, payload):
        # 过滤机器人自身的反应
        if payload.user_id == self.user.id:
            return
        if payload.message_id == config.POST_ID:
            channel = self.get_channel(payload.channel_id)
            message = await channel.fetch_message(payload.message_id)
            # 替换为API请求获取成员,替代缓存查询
            try:
                member = await message.guild.fetch_member(payload.user_id)
            except discord.NotFound:
                # 成员不存在直接返回
                return
            # 非空判断
            if not member:
                return
            try:
                emoji = str(payload.emoji)
                role = utils.get(message.guild.roles, id=config.ROLES[emoji])
                if not role:
                    return
                if(len([i for i in member.roles if i.id not in config.EXCROLES]) <= config.MAX_ROLES_PER_USER):
                    await member.add_roles(role)
                    print('[SUCCESS] User {0.display_name} has been granted with role {1.name}'.format(member, role))
                else:
                    await message.remove_reaction(payload.emoji, member)
                    print('[ERROR] Too many roles for user {0.display_name}'.format(member))
            except KeyError as e:
                print('[ERROR] KeyError, no role found for ' + emoji)
            except Exception as e:
                print(repr(e))
    async def on_raw_reaction_remove(self, payload):
        # 过滤机器人自身的反应
        if payload.user_id == self.user.id:
            return
        channel = self.get_channel(payload.channel_id)
        message = await channel.fetch_message(payload.message_id)
        # 替换为API请求获取成员
        try:
            member = await message.guild.fetch_member(payload.user_id)
        except discord.NotFound:
            return
        if not member:
            return
        try:
            emoji = str(payload.emoji)
            role = utils.get(message.guild.roles, id=config.ROLES[emoji])
            if not role:
                return
            await member.remove_roles(role)
            print('[SUCCESS] Role {1.name} has been remove for user {0.display_name}'.format(member, role))
        except KeyError as e:
            print('[ERROR] KeyError, no role found for ' + emoji)
        except Exception as e:
            print(repr(e))

# 初始化时传入意图参数
client = MyClient(intents=intents)
client.run(config.TOKEN)

内容的提问来源于stack exchange,提问作者Adrian Makridenko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 22:30:00