Discord.py反应身份组命令报错:'NoneType'对象无remove_roles属性
问题根因
报错触发的直接原因是on_raw_reaction_remove事件执行时,拿到的member对象为None,没有remove_roles属性,核心由两个代码错误导致:
- 重复初始化Bot实例,导致配置的Intents完全未生效:你先初始化了带Intents的
discord.Client,随后又重新赋值为commands.Bot,新的Bot实例没有传入Intents参数,成员缓存未开启,无法正常获取服务器成员对象。 on_raw_reaction_remove事件本身不会携带member属性,仅靠本地缓存的guild.get_member拉取成员,当用户不在本地缓存中时就会返回None。
额外可能触发问题的点:reactrole.json未初始化空数组首次读取报错、Bot角色权限低于要分配的身份组、Discord开发者后台未开启Server Members Intent。
修复步骤
- 修正Bot初始化逻辑,删除冗余的
discord.Client声明,直接给commands.Bot传入配置好的Intents - 优化
on_raw_reaction_remove事件的成员拉取逻辑,缓存不存在时主动调用接口拉取成员,增加非空判断跳过无效请求 - 排除Bot自身触发的反应移除事件
- 增加message_id匹配逻辑,避免多个反应消息用相同emoji时逻辑冲突
- 兼容reactrole.json不存在的场景,避免首次读取报错
- 检查Discord开发者后台的Privileged Gateway Intents中,Server Members Intent已开启,且Bot在服务器中的角色排序高于所有要分配的反应身份组,拥有Manage Roles权限
修正后的完整代码
import discord from discord.ext import commands import random from io import BytesIO import DiscordUtils from discord.utils import get import os import asyncio import aiohttp import datetime import json # 配置Intents intents = discord.Intents.all() intents.members = True # 直接给commands.Bot传入intents,删除冗余的discord.Client初始化 client = commands.Bot(command_prefix="?", case_insensitive = True, intents=intents) client.remove_command("help") @client.event async def on_raw_reaction_add(payload): if payload.member.bot: return with open('reactrole.json') as react_file: data = json.load(react_file) for x in data: if x['emoji'] == payload.emoji.name and x['message_id'] == payload.message_id: role = discord.utils.get(client.get_guild(payload.guild_id).roles, id=x['role_id']) if role: await payload.member.add_roles(role) @client.event async def on_raw_reaction_remove(payload): # 先排除Bot自己触发的事件 if payload.user_id == client.user.id: return guild = client.get_guild(payload.guild_id) if not guild: return # 优先从缓存拉取成员 member = guild.get_member(payload.user_id) # 缓存不存在就主动拉取 if not member: try: member = await guild.fetch_member(payload.user_id) except: # 拉取不到直接返回,比如用户已经退服 return with open('reactrole.json') as react_file: data = json.load(react_file) for x in data: # 增加message_id判断,避免多个反应消息冲突 if x['emoji'] == payload.emoji.name and x['message_id'] == payload.message_id: role = discord.utils.get(guild.roles, id=x['role_id']) if role and member: await member.remove_roles(role) @client.command(aliases = ['rr']) @commands.has_permissions(administrator=True, manage_roles=True) async def reactrole(ctx, emoji, role: discord.Role, *, message): emb = discord.Embed(title = "REACTION ROLE !",description=message,timestamp = datetime.datetime.utcnow(),color = 0xADD8E6) emb.set_thumbnail(url = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQPiUxyDTBu4dkC8f3tBeOzM8b0sEnK_8iLUg&usqp=CAU") emb.set_footer(icon_url = ctx.author.avatar_url, text = f"reactrole embed created by : {ctx.author.name}") emb.set_image(url = "https://www.logolynx.com/images/logolynx/f8/f843b4dd5ec5dc4e56a3f5639341516a.png") msg = await ctx.channel.send(embed=emb) await msg.add_reaction(emoji) # 兼容json文件不存在的情况 if not os.path.exists('reactrole.json'): with open('reactrole.json', 'w') as f: json.dump([], f) with open('reactrole.json') as json_file: data = json.load(json_file) new_react_role = {'role_name': role.name, 'role_id': role.id, 'emoji': emoji, 'message_id': msg.id} data.append(new_react_role) with open('reactrole.json', 'w') as f: json.dump(data, f, indent=4)
内容的提问来源于stack exchange,提问作者Ash
相关产品推荐
相关产品推荐

