{"record":{"id":"091d88f4331a3d78","repo":"siyuan-note/siyuan","slug":"decode-existing-session-data-failed-w","errorCode":null,"errorMessage":"decode existing session data failed: %w","messagePattern":"decode existing session data failed: %w","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"kernel/agent/session.go","lineNumber":353,"sourceCode":"\tdelete(newData, \"expectedRevision\")\n\tdelete(newData, \"commitTurnID\")\n\tdelete(newData, \"recoveryTurnID\")\n\tdelete(newData, \"recoveryState\")\n\tdelete(newData, \"recoveryRevision\")\n\tdelete(newData, \"agentRunning\")\n\tdelete(newData, \"lastCommittedTurnID\")\n\tcommitTurnID := meta.CommitTurnID\n\tif commitTurnID == \"\" {\n\t\tcommitTurnID = meta.RecoveryTurnID\n\t}\n\n\tcurrentRevision := int64(0)\n\tcurrentCommittedTurnID := \"\"\n\texisting, err := os.ReadFile(path)\n\tif err == nil && len(existing) > 0 {\n\t\tvar existingData map[string]any\n\t\tif err := gulu.JSON.UnmarshalJSON(existing, &existingData); err != nil {\n\t\t\treturn 0, nil, fmt.Errorf(\"decode existing session data failed: %w\", err)\n\t\t} else {\n\t\t\tcurrentRevision = numberToInt64(existingData[\"revision\"])\n\t\t\tcurrentCommittedTurnID, _ = existingData[\"lastCommittedTurnID\"].(string)\n\t\t\tif commitTurnID != \"\" && currentCommittedTurnID == commitTurnID {\n\t\t\t\t// 提交响应丢失后，客户端可能原样重试同一个 commitTurnID。此判断要先于修订号校验，\n\t\t\t\t// 并且不能再用客户端快照覆盖已经由 runtime 生成的权威内容。\n\t\t\t\tif err := markRuntimeCommittedLocked(meta.ID, commitTurnID); err != nil {\n\t\t\t\t\tlogging.LogWarnf(\"clean committed agent runtime failed: %s\", err)\n\t\t\t\t}\n\t\t\t\treturn currentRevision, existingData, nil\n\t\t\t}\n\t\t\tif meta.ExpectedRevision != nil && *meta.ExpectedRevision != currentRevision {\n\t\t\t\treturn currentRevision, nil, ErrSessionConflict\n\t\t\t}\n\t\t\tfor k, v := range existingData {\n\t\t\t\tif _, ok := newData[k]; !ok {\n\t\t\t\t\t// messages 是已废弃的旧会话字段，不再带入新格式；其他未知字段原样保留，\n\t\t\t\t\t// 避免前后端版本不一致时擦除较新版本写入的数据。","sourceCodeStart":335,"sourceCodeEnd":371,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/afa823b6b4e4f183511e0bc0a3be93caa94c7c97/kernel/agent/session.go#L335-L371","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// Health check: verify the on-disk session still parses before a critical save\nconst s = await fetchPost('/api/ai/agent/getSession', {id}); // fails fast if session.json is corrupt\nif (s.code === -1 && /decode existing/i.test(s.msg)) { /* quarantine session, alert user */ }","typeGuard":"null","tryCatchPattern":"catch (e) {\n  if (/decode existing session data/.test(e?.data?.msg ?? '')) {\n    // stop saving; offer restore-from-backup or removeSession to reset\n  }\n}","preventionTips":["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"],"tags":["agent","session","corruption","disk"],"backgroundTag":"corrupted-json-file","analyzedSha":"afa823b6b4e4f183511e0bc0a3be93caa94c7c97","analyzedAt":"2026-08-18T17:04:10.865Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}