Discord.py mute命令报JSONDecodeError: Expecting value错误
问题原因
- 你遇到的
JSONDecodeError: Expecting value: line 1 column 1 (char 0)本质是JSON文件格式损坏导致解析失败,根因是使用r+模式同时读写文件时,没有处理文件指针位置,也没有在写入前截断旧内容:- 用
r+打开文件后指针默认在开头,json.load()读完所有内容后指针会停在文件末尾 - 此时直接调用
json.dump()会把新的JSON内容追加在旧内容后面,导致单文件内存在多个JSON对象,属于非法格式 - 后续如果出现写入中断、指针偏移异常,还可能直接把文件写空,读取时起始位置没有合法JSON值,就会抛出char 0位置的解析错误
- 用
- 代码里还有两个影响功能的隐藏bug:
- 禁言时使用
member.edit(roles=[mute])会清空用户所有原有角色,仅保留禁言角色,不符合常规禁言逻辑 - 两处获取禁言角色的逻辑不统一,加入事件按角色名匹配、禁言命令按角色ID匹配,后续修改角色名会导致功能失效
- 禁言时使用
修复方案
彻底放弃r+同时读写的模式,JSON文件操作统一拆成「只读加载数据→修改内存数据→覆盖写入文件」三步,完全规避文件指针问题,是操作本地JSON文件最稳妥的实现方式。
- 先删除已经被写坏的
users.json,重新新建同名文件,写入初始合法内容:
{ "muted": [] }
- 替换业务代码为以下修复后的版本,记得提前把全局的禁言角色ID替换为你服务器实际的禁言角色ID:
import json import discord from discord.ext import commands # 全局统一配置禁言角色ID,避免多处维护出错 MUTE_ROLE_ID = 你的禁言角色实际ID @bot.event async def on_member_join(member): # 只读加载禁言列表 with open('users.json', 'r', encoding='utf-8') as fp: mute_data = json.load(fp) # 统一用ID获取禁言角色,不受角色名修改影响 mute_role = member.guild.get_role(MUTE_ROLE_ID) if mute_role and member.id in mute_data['muted']: await member.add_roles(mute_role) class Moderation(commands.Cog): @bot.command() async def mute(ctx, member: discord.Member): mute_role = ctx.guild.get_role(MUTE_ROLE_ID) if not mute_role: await ctx.send("禁言角色配置错误,请检查角色ID") return # 追加禁言角色,不清空用户原有角色 await member.add_roles(mute_role) # 第一步:读取现有禁言数据 with open('users.json', 'r', encoding='utf-8') as fp: mute_data = json.load(fp) # 第二步:更新内存中的禁言列表 if member.id not in mute_data['muted']: mute_data['muted'].append(member.id) # 第三步:覆盖写入文件,从根源避免指针问题 with open('users.json', 'w', encoding='utf-8') as fp: json.dump(mute_data, fp, indent=2) await ctx.send(f"已将用户{member.mention}加入禁言列表")
注意事项
- 运行脚本时确保工作目录和
users.json存放目录一致,避免程序找不到文件时自动创建空文件触发解析错误 - 所有文件打开操作统一指定
encoding='utf-8',避免Windows系统默认GBK编码导致的特殊字符解析异常 - 后续实现
unmute解除禁言功能时,只需要在逻辑中把对应用户ID从mute_data['muted']列表移除,再按相同的覆盖写逻辑保存文件即可
内容的提问来源于stack exchange,提问作者toxxicity
相关产品推荐
相关产品推荐

