Bug Description
Session state JSON files become corrupted due to concurrent write race conditions, causing JSONDecodeError: Extra data on every subsequent request to the affected session. Once corrupted, the session is permanently broken (all messages return 422) until the file is manually repaired.
Reproduction
Running CoPaw with QQ channel over several hours. The session file grows to ~400KB+. Concurrent save_session_state / update_session_state calls interleave their writes, producing a file with a valid JSON object followed by garbage fragments.
Error log:
ERROR copaw/app/runner/runner.py:564 | Error in query handler: [422] AGENT_UNKNOWN_ERROR:
Unknown agent error: JSONDecodeError: Extra data: line 1 column 321545 (char 321544)
Corrupted file analysis:
File size: 321561 chars
First JSON object ends at char 321544
Remaining chars: 17
Remaining content: '==============\"}}'
Root Cause
SafeJSONSession has three file operations (save_session_state, update_session_state, get_session_state_dict) accessing the same session file without any locking. save_session_state uses synchronous open("w") while load_session_state/update_session_state use aiofiles. When two coroutines execute open("w") nearly simultaneously, OS-level writes interleave, producing concatenated JSON fragments.
Proposed Fix
Add JSONDecodeError catch with raw_decode fallback at all three json.loads call sites in SafeJSONSession. When corruption is detected, the first valid JSON object is extracted and a warning is logged, instead of crashing.
Environment
- CoPaw version: 1.0.2
- Channel: QQ
- Python: 3.13
- OS: Ubuntu 25.10
Bug Description
Session state JSON files become corrupted due to concurrent write race conditions, causing
JSONDecodeError: Extra dataon every subsequent request to the affected session. Once corrupted, the session is permanently broken (all messages return 422) until the file is manually repaired.Reproduction
Running CoPaw with QQ channel over several hours. The session file grows to ~400KB+. Concurrent
save_session_state/update_session_statecalls interleave their writes, producing a file with a valid JSON object followed by garbage fragments.Error log:
Corrupted file analysis:
Root Cause
SafeJSONSessionhas three file operations (save_session_state,update_session_state,get_session_state_dict) accessing the same session file without any locking.save_session_stateuses synchronousopen("w")whileload_session_state/update_session_stateuseaiofiles. When two coroutines executeopen("w")nearly simultaneously, OS-level writes interleave, producing concatenated JSON fragments.Proposed Fix
Add
JSONDecodeErrorcatch withraw_decodefallback at all threejson.loadscall sites inSafeJSONSession. When corruption is detected, the first valid JSON object is extracted and a warning is logged, instead of crashing.Environment