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

discord.py警告系统warn命令触发KeyError报错问题排查

报错根因

触发KeyError: '472100676407656448'是因为你在累加用户警告数时,没有提前校验该用户ID是否存在于warns.json存储的字典中:第一次给某个用户发警告时,字典里没有对应用户ID的键,直接执行+=1操作就会抛出键不存在的错误。
除此之外你的代码还有几个会影响运行的隐性问题:

  • warns_check函数直接返回了全量警告字典,没有提取单个用户的警告数值,调用warnings命令时会输出所有用户的警告数据,不符合预期
  • remove_warn函数同样没有做键存在校验,也没有限制扣减后的警告数不能小于0,会触发同类KeyError,或者出现负数警告数的逻辑错误
  • 没有处理warns.json文件不存在、内容为空的初始化场景,第一次运行代码读文件就会报错
  • 三个工具函数传入的ctx参数全程没有被使用,属于冗余传参
  • 没有处理用户关闭私信、操作对象是机器人/操作者本人、扣减警告数为负数等边界场景,容易触发异常
修复后代码
import json
import os
import discord
from discord.ext import commands

# 首次运行自动初始化警告存储文件
if not os.path.exists('warns.json'):
    with open('warns.json', 'w', encoding='utf-8') as f:
        json.dump({}, f)

def save_warn(member: discord.Member):
    with open('warns.json', 'r', encoding='utf-8') as f:
        warns = json.load(f)
    user_id = str(member.id)
    # 无该用户警告记录时默认从0开始累加
    warns[user_id] = warns.get(user_id, 0) + 1
    with open('warns.json', 'w', encoding='utf-8') as f:
        json.dump(warns, f, indent=2)

def remove_warn(member: discord.Member, amount: int):
    with open('warns.json', 'r', encoding='utf-8') as f:
        warns = json.load(f)
    user_id = str(member.id)
    current_warns = warns.get(user_id, 0)
    # 扣减后警告数最小为0,不出现负数
    warns[user_id] = max(current_warns - amount, 0)
    with open('warns.json', 'w', encoding='utf-8') as f:
        json.dump(warns, f, indent=2)
    
def warns_check(member: discord.Member):
    with open('warns.json', 'r', encoding='utf-8') as f:
        warns = json.load(f)
    user_id = str(member.id)
    # 仅返回当前查询用户的警告数,无记录时返回0
    return warns.get(user_id, 0)

@bot.command()
@commands.has_permissions(kick_members=True)
async def warn(ctx, member: discord.Member, *, reason):
    # 拦截无效操作
    if member.bot or member == ctx.author:
        await ctx.send("无法对该用户执行警告操作")
        return
    save_warn(member)
    dm = await bot.fetch_user(member.id)
    em = discord.Embed(title="服务器警告", description=f"来源服务器: {ctx.guild.name}\n警告原因: {reason}")
    # 处理用户关闭私信的场景,避免抛错
    try:
        await dm.send(embed=em)
    except discord.Forbidden:
        pass
    await ctx.send(f"已给 {member.mention} 记1次警告,原因:{reason}")

@bot.command()
@commands.has_permissions(kick_members=True)
async def warnings(ctx, member: discord.Member):
    warn_count = warns_check(member)
    await ctx.send(f"{member.name} 当前共有 {warn_count} 次警告。")

@bot.command()
@commands.has_permissions(kick_members=True)
async def rmwarn(ctx, member: discord.Member, amount: int):
    if amount <= 0:
        await ctx.send("扣除的警告数值必须大于0")
        return
    remove_warn(member, amount)
    await ctx.send(f"已移除 {member.name} 的 {amount} 次警告!")
调整说明
  • 所有文件读写加了encoding='utf-8',避免不同系统下中文乱码
  • 写入json时加了indent=2参数,生成的存储文件格式清晰,方便手动修改调整
  • 补全了所有边界场景的判断,避免无意义的报错
  • 移除了工具函数中冗余的ctx传参,减少不必要的参数传递

内容的提问来源于stack exchange,提问作者Monster png

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 17:51:23