CoPaw 1.0.2 会话状态 JSON 损坏问题排查与修复实战

问题现象

在使用 CoPaw 1.0.2 过程中,Web 页面可以正常打开,但访问聊天记录或执行 Agent 任务时出现异常。

日志中出现类似错误:

GET /api/chats HTTP/1.1" 500 Internal Server Error

json.decoder.JSONDecodeError:
Expecting value: line 1 column 1 (char 0)

或者:

AGENT_UNKNOWN_ERROR:
Unknown agent error: JSONDecodeError:
Expecting value: line 1 column 1 (char 0)

§

第一阶段分析:聊天记录接口异常

最初发现:

GET /api/models ... 200 OK
GET /api/chats ... 500 Internal Server Error

说明:

  • 模型服务正常
  • FastAPI 正常
  • Uvicorn 正常
  • CoPaw 主程序正常

仅聊天接口失败。

调用栈显示:

json_repo.py
↓
json.loads(...)
↓
JSONDecodeError

初步判断为:

某个 JSON 数据文件为空或损坏。


§

第二阶段分析:Agent 执行失败

随后出现新的错误:

ERROR runner.py:564

Error in query handler:
[422] AGENT_UNKNOWN_ERROR

完整堆栈:

await self.session.load_session_state(...)

最终定位:

File "...session.py", line 114

states = json.loads(content)

异常:

json.decoder.JSONDecodeError:
Expecting value: line 1 column 1 (char 0)

§

JSONDecodeError 的真实含义

Python 源码:

states = json.loads(content)

报错:

JSONDecodeError:
Expecting value: line 1 column 1 (char 0)

通常意味着:

content == ""

或者:

content == "\n"

即:

文件为空。


§

查看 CoPaw 源码

打开:

D:\soft\Python\Python312\Lib\site-packages\
copaw\app\runner\session.py

关键代码:

session_save_path = self._get_save_path(
    session_id,
    user_id=user_id
)

async with aiofiles.open(
    session_save_path,
    "r"
) as f:
    content = await f.read()

    states = json.loads(content)

问题发生在:

states = json.loads(content)

如果文件为空:

content == ""

就会直接崩溃。


§

进一步分析文件命名规则

查看源码:

def _get_save_path(
    self,
    session_id,
    user_id
):

文件名生成规则:

safe_uid = sanitize_filename(user_id)

file_path = f"{safe_uid}_{safe_sid}.json"

例如:

user_id = "default"
session_id = "1776088022970"

生成:

default_1776088022970.json

§

从错误文件中获取关键参数

CoPaw 自动生成了错误诊断文件:

C:\Users\Administrator\AppData\Local\Temp\
copaw_query_error_30g3e65h.json

内容:

{
  "session_id": "1776088022970",
  "user_id": "default"
}

因此可以推断:

损坏文件很可能是:

default_1776088022970.json

§

如何定位损坏文件

方法一:搜索 Session 文件

PowerShell:

Get-ChildItem C:\Users\Administrator\.copaw `
-Recurse `
-Filter "*.json" |
Where-Object {
    $_.Name -match "1776088022970"
}

§

方法二:搜索空 JSON

Get-ChildItem `
$env:USERPROFILE `
-Recurse `
-Filter *.json `
-ErrorAction SilentlyContinue |
Where-Object {
    $_.Length -eq 0
}

重点关注:

.copaw
session
state

相关目录。


§

方法三:打印真实路径

修改源码:

print(session_save_path)

即:

async with aiofiles.open(
    session_save_path,
    "r"
) as f:

    print(session_save_path)

    content = await f.read()

    states = json.loads(content)

重新运行即可看到真实文件路径。


§

修复方案

方案一:删除损坏文件

如果不需要恢复状态:

Remove-Item default_1776088022970.json

重新启动 CoPaw。

系统会自动重新创建。


§

方案二:手工修复

将空文件内容改为:

{}

保存。

重新启动。


§

方案三:增强容错(推荐)

修改:

states = json.loads(content)

为:

if not content.strip():
    states = {}
else:
    states = json.loads(content)

或者:

try:
    states = json.loads(content)
except json.JSONDecodeError:
    states = {}

这样即使文件异常为空,也不会导致整个 Agent 崩溃。


§

根本原因分析

这种问题通常发生于:

1. 强制关闭程序

例如:

任务管理器结束进程
关闭终端
系统异常重启

文件写入中断:

0 KB

§

2. 磁盘异常

例如:

网络盘
同步盘
U盘

写入失败。


§

3. 程序异常退出

保存流程:

open(file)
write(...)

尚未完成:

JSON内容

进程已崩溃。

最终留下空文件。


§

最终结论

本次故障并非:

  • OpenAI API 问题
  • 模型问题
  • FastAPI 问题
  • AgentScope Runtime 问题

真正原因是:

CoPaw Session State 文件为空

导致:

json.loads(content)

解析失败。

结合 Session ID:

1776088022970

和 User ID:

default

可以锁定对应状态文件:

default_1776088022970.json

删除或修复该文件后,系统即可恢复正常。

同时建议在 CoPaw 的 session.py 中增加空文件容错处理,避免未来再次出现同类故障。