You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用discord.py编写等级查询命令?JSONDecodeError报错如何修复?

问题根因

你的报错json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)本质是读取users.json时,文件为空或者内容不符合JSON格式,导致解析失败。主要触发原因有三个:

  1. on_message事件中bot.process_commands位置错误:该方法被嵌套在非机器人用户消息的判断逻辑、以及JSON写入的缩进块内,只有普通用户发消息且完成经验写入后才会触发命令解析;且w模式打开JSON文件时会先清空内容,写入完成前如果触发level命令读文件,就会读到空内容。
  2. 初始化users.json的逻辑存在漏洞:原初始化代码的文件句柄没有规范关闭,特殊场景下会导致文件内容写入异常,生成空JSON文件。
  3. 缺少异常处理:读写JSON的逻辑没有兼容文件损坏/内容为空的场景,一旦出现异常就直接抛出错误。
修复方案

1. 修正on_message事件逻辑

调整bot.process_commands的位置到if判断外,确保所有消息都能正常解析命令,同时增加JSON读取异常兼容:

@bot.event    
async def on_message(message):
    # 仅处理普通用户的经验更新逻辑
    if not message.author.bot:
        # 兼容JSON损坏的场景,读失败默认初始化为空字典
        try:
            with open('users.json', 'r') as f:
                users = json.load(f)
        except json.decoder.JSONDecodeError:
            users = {}
        await add_experience(users, message.author)
        await level_up(users, message.author, message)
        with open('users.json', 'w') as f:
            json.dump(users, f, indent=4) # 加indent方便手动排查JSON结构
    # 所有消息都要走命令解析,和if判断同级,不要嵌套在内部
    await bot.process_commands(message)

2. 替换JSON文件初始化逻辑

删除原有的混乱初始化代码,替换成更安全的写法,避免文件操作异常:

import os
# 不存在文件或者文件为空时,初始化写入空JSON对象
if not os.path.exists("users.json") or os.stat("users.json").st_size == 0:
    with open("users.json", "w") as f:
        json.dump({}, f)
# 读取初始用户数据
with open('users.json', 'r') as f:
    users = json.load(f)

3. 优化level命令逻辑

增加异常捕获和用户不存在的兼容场景,避免报错:

@bot.command()
async def level(ctx, member: discord.Member = None):
    target = member if member else ctx.author
    # 捕获JSON读取异常
    try:
        with open('users.json', 'r') as f:
            users = json.load(f)
    except json.decoder.JSONDecodeError:
        await ctx.send("等级数据读取失败,请稍后重试")
        return
    # 兼容用户没有发送过消息、没有数据的场景
    if str(target.id) not in users:
        tip = f"{target.display_name} 还没有等级数据,先发几条消息获取经验吧~"
        await ctx.send(tip)
        return
    lvl = users[str(target.id)]['level']
    if member:
        await ctx.send(f"{target.display_name} 当前等级为 {lvl}!")
    else:
        await ctx.send(f"你当前的等级为 {lvl}!")

可选进阶优化(高并发场景)

如果服务器用户量较大,频繁读写JSON容易出现写入中途被读取的问题,可以用原子写入的方式避免:

import shutil
# 把原来的写JSON逻辑替换为以下内容
with open('users.tmp', 'w') as f:
    json.dump(users, f, indent=4)
# 写完临时文件后直接替换原文件,不会出现中间读取到空内容的问题
shutil.move('users.tmp', 'users.json')

内容的提问来源于stack exchange,提问作者Just Otartist

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 10:57:03