siyuan-note/siyuan · error
decode existing session data failed: %w
Error message
decode existing session data failed: %w
What it means
When saving, SaveSessionState reads the existing data/storage/ai/agent/sessions/<id>/session.json to compute the current revision (kernel/agent/session.go:349-353). If the file exists and is non-empty but is not valid JSON, the save aborts with 'decode existing session data failed' — the on-disk session is corrupt, so the kernel refuses to guess a revision or overwrite authoritative content blindly.
Source
Thrown at kernel/agent/session.go:353
delete(newData, "expectedRevision")
delete(newData, "commitTurnID")
delete(newData, "recoveryTurnID")
delete(newData, "recoveryState")
delete(newData, "recoveryRevision")
delete(newData, "agentRunning")
delete(newData, "lastCommittedTurnID")
commitTurnID := meta.CommitTurnID
if commitTurnID == "" {
commitTurnID = meta.RecoveryTurnID
}
currentRevision := int64(0)
currentCommittedTurnID := ""
existing, err := os.ReadFile(path)
if err == nil && len(existing) > 0 {
var existingData map[string]any
if err := gulu.JSON.UnmarshalJSON(existing, &existingData); err != nil {
return 0, nil, fmt.Errorf("decode existing session data failed: %w", err)
} else {
currentRevision = numberToInt64(existingData["revision"])
currentCommittedTurnID, _ = existingData["lastCommittedTurnID"].(string)
if commitTurnID != "" && currentCommittedTurnID == commitTurnID {
// 提交响应丢失后,客户端可能原样重试同一个 commitTurnID。此判断要先于修订号校验,
// 并且不能再用客户端快照覆盖已经由 runtime 生成的权威内容。
if err := markRuntimeCommittedLocked(meta.ID, commitTurnID); err != nil {
logging.LogWarnf("clean committed agent runtime failed: %s", err)
}
return currentRevision, existingData, nil
}
if meta.ExpectedRevision != nil && *meta.ExpectedRevision != currentRevision {
return currentRevision, nil, ErrSessionConflict
}
for k, v := range existingData {
if _, ok := newData[k]; !ok {
// messages 是已废弃的旧会话字段,不再带入新格式;其他未知字段原样保留,
// 避免前后端版本不一致时擦除较新版本写入的数据。View on GitHub (pinned to afa823b6b4)
Solutions
- Inspect workspace/data/storage/ai/agent/sessions/<id>/session.json — confirm where the JSON breaks (truncation vs. merge conflict markers)
- Restore the file from your backup or the sync tool's conflict copy
- If the session is disposable, DELETE /api/ai/agent/removeSession and let the client create a fresh session (history in that session is lost)
- If it recurs, stop putting the workspace on a cloud-synced folder and check disk health
Defensive patterns
Strategy: fallback
Validate before calling
// Health check: verify the on-disk session still parses before a critical save
const s = await fetchPost('/api/ai/agent/getSession', {id}); // fails fast if session.json is corrupt
if (s.code === -1 && /decode existing/i.test(s.msg)) { /* quarantine session, alert user */ } Type guard
null
Try / catch
catch (e) {
if (/decode existing session data/.test(e?.data?.msg ?? '')) {
// stop saving; offer restore-from-backup or removeSession to reset
}
} Prevention
- Keep the workspace out of cloud-sync folders, or pause sync while the agent runs
- Back up data/storage/ai/agent/sessions before manual edits
- Never hand-edit session.json while a session is running
When it happens
Trigger: POST /api/ai/agent/saveSession for a session whose session.json was truncated by a crash/power-loss mid-write, hand-edited and broken, mangled by a third-party sync tool (Dropbox/OneDrive partial sync), or written by an incompatible older/newer version.
Common situations: Hard kill during agent turn commit; workspace synced through a cloud drive that produced a conflict file or zero-length file; users editing session.json manually to rename or prune history; disk-level corruption.
Related errors
- agent session revision conflict
- invalid session id
- invalid session data
- decode session data failed: %w
- read session file failed: %w
AI-assisted analysis of siyuan-note/siyuan@afa823b6b4 (2026-08-18).
Data as JSON: /api/errors/091d88f4331a3d78.
Report an issue: GitHub.