Discord.py多服务器欢迎消息机器人触发ctx相关AttributeError报错
问题根因
报错的核心原因是在on_member_join事件回调中错误使用了仅在命令场景下存在的ctx对象:
on_member_join是由Discord服务器成员入服事件触发的回调,触发时不会生成命令上下文ctx(该对象仅在用户输入指令、被命令解析器处理时生成)- 该回调的作用域内从未定义过
ctx变量,Python运行时意外匹配到了同名的第三方/内置ctx模块,才会抛出AttributeError: module 'ctx' has no attribute 'message'的报错。
代码还存在两个隐藏的兼容问题,即使修复上述报错也会导致后续运行异常:
- JSON格式的键仅支持字符串类型,使用整数类型的服务器ID作为键存储时,序列化后会被自动转为字符串,后续用整数ID取值时会触发
KeyError - 若使用2.0及以上版本的discord.py,
member.avatar_url、member.guild.icon_url这类旧属性已被弃用,未调整会触发属性访问报错
修复方案
- 移除事件回调中对
ctx的所有依赖
事件回调的入参member本身就携带了所属服务器的全部信息,直接通过member.guild.id即可获取服务器标识,无需借助ctx取值。 - 统一JSON键的类型
存储配置时显式将数字类型的服务器ID转为字符串作为键,取值时也传入字符串格式的ID匹配,避免序列化/反序列化的类型不匹配问题。 - 补充必要容错逻辑
对未配置欢迎频道的服务器、频道已被删除、机器人无频道发消息权限的场景做判断兜底,避免额外运行报错。
修正后完整代码
@client.command() @commands.has_permissions(administrator=True) async def welcomeMessage(ctx): with open("guild.json", "r") as f: guildInfo = json.load(f) # 显式将服务器ID转为字符串作为JSON键,避免类型不匹配 guildInfo[str(ctx.guild.id)] = ctx.channel.id with open("guild.json", "w") as f: json.dump(guildInfo, f, indent=2) @client.event async def on_member_join(member): with open("guild.json", "r") as f: guildInfo = json.load(f) # 从入参member获取所属服务器ID,转为字符串匹配JSON键 guild_id_str = str(member.guild.id) # 未配置欢迎频道时直接退出,避免KeyError if guild_id_str not in guildInfo: return channel_id = guildInfo[guild_id_str] # 获取真实频道对象,校验频道有效性,避免无权限/频道删除导致报错 channel = member.guild.get_channel(channel_id) if not channel: return embed = discord.Embed(colour=0x07faf6, description=f"***Welcome to the Server***") # 替换为新版discord.py支持的头像/图标访问方式 embed.set_thumbnail(url=member.avatar.url) embed.set_author(name=member.name, icon_url=member.avatar.url) embed.set_footer(text=member.guild, icon_url=member.guild.icon.url) embed.timestamp = datetime.datetime.utcnow() await channel.send(embed=embed)
内容的提问来源于stack exchange,提问作者McBigBob
相关产品推荐
相关产品推荐

