discord.py自定义欢迎频道功能失效KeyError报错排查
问题根因
一共3个直接导致功能失效的问题:
- 配置文件读写路径不统一:
set_welcome_channel命令读写的是项目根目录下的guilds.json,但on_member_join事件读取的是data/guilds.json,两个文件完全独立,新成员加入时读取的配置文件里根本没有对应服务器的频道配置,直接抛出KeyError。 - 频道对象类型错误:JSON存储的频道ID是字符串格式,直接把ID字符串当成频道实例调用
.send()方法,就算KeyError解决了这里也会报属性错误,发不出消息。 - 日志编码问题:
on_message事件里写日志文件时没有指定编码,Windows系统默认用cp1252编码打开文件,遇到消息里的零宽空格(\u200b)就会抛出编码错误,打断事件执行流程。
修复步骤
- 统一配置文件路径,建议抽成全局常量避免写错,提前创建好
data目录避免文件找不到报错。 - 从配置读取到频道ID后,转成整数类型,通过公会对象查询到实际的频道实例再发送消息。
- 增加容错判断:如果服务器没有配置过欢迎频道、或者配置的频道已被删除,直接跳过逻辑不要抛错。
- 打开所有读写文本/JSON的文件时统一指定
encoding='utf-8',避免编码报错;头像地址改用member.display_avatar.url兼容无自定义头像的成员场景。
修复后可直接运行的代码
import json import random import discord from discord.ext import commands from easy_pil import Editor, load_image_async, Font, File # 替换成你自己的机器人前缀,Intents必须开启成员权限 client = commands.Bot(command_prefix="!", intents=discord.Intents.all()) # 统一配置路径,避免读写不一致 WELCOME_CONFIG_PATH = "data/guilds.json" @client.event async def on_member_join(member): # 读取配置,兼容文件不存在/格式损坏场景 try: with open(WELCOME_CONFIG_PATH, 'r', encoding='utf-8') as f: guilds_dict = json.load(f) except (FileNotFoundError, json.JSONDecodeError): guilds_dict = {} guild_id_str = str(member.guild.id) # 未配置欢迎频道直接退出,不抛错 if guild_id_str not in guilds_dict: return # 转换ID类型,获取真实频道实例 channel_id = int(guilds_dict[guild_id_str]) welcome_channel = member.guild.get_channel(channel_id) # 频道已删除/无权限访问直接退出 if not welcome_channel or not isinstance(welcome_channel, discord.TextChannel): return # 生成欢迎图片 background = Editor("pic.png") # 兼容未设置自定义头像的成员 profile_image = await load_image_async(str(member.display_avatar.url)) profile = Editor(profile_image).resize((150, 150)).circle_image() poppins = Font.poppins(size=50, variant="bold") poppins_small = Font.poppins(size=20, variant="light") random_color = ["black", "white", "blue", "red", "green", "cyan", "brown", "orange", "yellow", "gray", "purple"] background.paste(profile, (325, 90)) background.ellipse((325, 90), 150, 150, outline=random.choice(random_color), stroke_width=5) # 文字描边逻辑 for offset in [(-2,-2),(2,-2),(-2,2),(2,2)]: background.text((400+offset[0], 260+offset[1]), f"WELCOME TO {member.guild.name}", font=poppins, color="black", align="center") background.text((400, 260), f"WELCOME TO {member.guild.name}", color="white", font=poppins, align="center") for offset in [(-1,-1),(1,-1),(-1,1),(1,1)]: background.text((400+offset[0], 325+offset[1]), f"{member.name}#{member.discriminator}", font=poppins_small, color="black", align="center") background.text((400, 325), f"{member.name}#{member.discriminator}", color="white", font=poppins_small, align="center") file = File(fp=background.image_bytes, filename="welcome.png") await welcome_channel.send(f"Hello {member.mention}") await welcome_channel.send(file=file) @client.command(name='welcome') @commands.has_permissions(administrator=True) # 仅管理员可修改配置 async def set_welcome_channel(ctx, channel: discord.TextChannel): try: with open(WELCOME_CONFIG_PATH, 'r', encoding='utf-8') as f: guilds_dict = json.load(f) except (FileNotFoundError, json.JSONDecodeError): guilds_dict = {} guilds_dict[str(ctx.guild.id)] = str(channel.id) with open(WELCOME_CONFIG_PATH, 'w', encoding='utf-8') as f: json.dump(guilds_dict, f, indent=4, ensure_ascii=False) await ctx.send(f'已将本服欢迎消息发送频道设置为:{channel.mention}') # 修复日志编码问题示例 @client.event async def on_message(message): # 写日志必须指定utf-8编码 with open("message_log.txt", "a", encoding="utf-8") as text_file: print(f"{message.guild} {message.author} {message.id} {message.content}", file=text_file) # 必须加这行,否则前缀命令不会触发 await client.process_commands(message)
额外注意点
- 必须在Discord开发者后台开启机器人的「服务器成员意图」(Server Members Intent),否则
on_member_join事件根本不会触发。 - 确保机器人拥有欢迎频道的发送消息、嵌入文件权限,否则消息会发送失败。
内容的提问来源于stack exchange,提问作者ItzJustas
相关产品推荐
相关产品推荐

