Discord.py on_member_remove事件报NoneType对象无send属性错误
报错原因
控制台抛出AttributeError: 'NoneType' object has no attribute 'send'的直接原因是bot.get_channel(id=myLogChannelIdHere)返回了None,即机器人没有从本地缓存中找到对应ID的频道。你写在on_ready里的同逻辑代码可以正常运行,是因为on_ready的触发节点恰好是机器人首次完成全局缓存加载的时刻,此时频道数据已经存入缓存;而成员加入/离开事件触发时,大概率遇到了以下问题:
- 未开启Discord要求的特权网关意图(核心是Server Members Intent),导致机器人无法完整同步服务器的频道、成员数据,缓存缺失
bot.get_channel()仅读取本地缓存,在机器人刚启动、断线重连等缓存未加载/刷新完成的场景下,即使频道ID完全正确,也会返回None- 你当前编写的Embed代码存在语法错误,即使频道获取正常,后续也会触发其他运行时异常
修复方案
1. 配置特权网关意图
首先前往Discord开发者门户,进入你的机器人应用的「Bot」设置页,下拉到Privileged Gateway Intents板块,开启以下三个开关后保存:
- Server Members Intent(接收成员加入/离开事件的强制要求)
- Message Content Intent
- Presence Intent
随后修改机器人初始化代码,显式声明启用的intents:
import discord from discord.ext import commands import datetime # 替换为你自己的配置,注意频道ID必须是整数类型,不要加引号 BOT_PREFIX = "!" MY_LOG_CHANNEL_ID = 123456789012345678 intents = discord.Intents.default() intents.members = True intents.guilds = True intents.messages = True bot = commands.Bot(command_prefix=BOT_PREFIX, intents=intents)
2. 优化频道获取逻辑,增加兜底判断
不要在每个事件中重复调用get_channel,建议在on_ready触发时将日志频道实例存为全局变量,同时增加API兜底逻辑,避免缓存失效导致程序崩溃:
# 全局变量存储日志频道实例 log_channel = None @bot.event async def on_ready(): global log_channel # 每次触发on_ready(包括断线重连)都重新获取频道实例,保证缓存有效 log_channel = bot.get_channel(MY_LOG_CHANNEL_ID) # 缓存读取失败时,主动调用API获取频道做兜底 if not log_channel: try: log_channel = await bot.fetch_channel(MY_LOG_CHANNEL_ID) except Exception as e: print(f"日志频道获取失败: {str(e)}") return await bot.change_presence( status=discord.Status.online, activity=discord.Activity(type=discord.ActivityType.watching, name="") ) await log_channel.send("Le bot est en ligne") print(f"{bot.user.name} est en ligne")
3. 修正成员离开事件的代码错误
你原有代码存在三处语法问题:一是set_thumbnail是Embed的实例方法,不是构造函数的传入参数;二是f字符串中多写了多余的$符号;三是discord.py 2.0+版本中,成员头像地址需要通过member.avatar.url获取,旧属性avatar_url已经废弃。修正后的代码如下:
@bot.event async def on_member_remove(member): global log_channel # 频道实例不存在时直接终止逻辑,避免抛出空值错误 if not log_channel: return embed = discord.Embed( title="**🚪 Un membre est parti**", description=f"{member} a quitté le serveur", color=0xda291c ) # 正确设置头像缩略图,成员无自定义头像时跳过避免报错 if member.avatar: embed.set_thumbnail(url=member.avatar.url) embed.timestamp = datetime.datetime.utcnow() await log_channel.send(embed=embed)
注意事项
- 提前确认机器人在日志频道拥有发送消息、嵌入链接的权限,权限不足同样会导致消息发送失败
on_ready事件会在机器人每次断线重连时触发,将频道获取逻辑放在此处可以自动更新缓存的频道实例,避免机器人长期运行后缓存失效- 所有ID类配置(频道ID、服务器ID、用户ID)都必须传入整数类型,传入字符串会导致
get_channel无法匹配到对应资源
内容的提问来源于stack exchange,提问作者Max.
相关产品推荐
相关产品推荐

