{"record":{"id":"b7409775d88fae7d","repo":"siyuan-note/siyuan","slug":"agent-runtime-user-entry-not-found","errorCode":null,"errorMessage":"agent runtime user entry not found","messagePattern":"agent runtime user entry not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/agent/runtime.go","lineNumber":288,"sourceCode":"\t\t}\n\t\tif !committed {\n\t\t\treturn fmt.Errorf(\"agent session has an uncommitted turn\")\n\t\t}\n\t\truntime.ActiveTurn = nil\n\t}\n\tdata, err := os.ReadFile(filepath.Join(sessionsDir(), sessionID, \"session.json\"))\n\tif err != nil {\n\t\treturn err\n\t}\n\tvar session map[string]any\n\tif err := gulu.JSON.UnmarshalJSON(data, &session); err != nil {\n\t\treturn err\n\t}\n\tif turn.BaseRevision >= 0 && numberToInt64(session[\"revision\"]) != turn.BaseRevision {\n\t\treturn ErrSessionConflict\n\t}\n\tif findRuntimeUserAnchor(session, turn.UserEntryID) < 0 {\n\t\treturn fmt.Errorf(\"agent runtime user entry not found\")\n\t}\n\truntime.ActiveTurn = turn\n\treturn writeRuntimeLocked(sessionID, runtime)\n}\n\nfunc isTurnCommittedLocked(sessionID, turnID string) (bool, error) {\n\tdata, err := os.ReadFile(filepath.Join(sessionsDir(), sessionID, \"session.json\"))\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tvar meta sessionMeta\n\tif err := gulu.JSON.UnmarshalJSON(data, &meta); err != nil {\n\t\treturn false, err\n\t}\n\treturn meta.LastCommittedTurnID == turnID, nil\n}\n\nfunc saveRuntimeTurn(sessionID string, turn *agentRuntimeTurn) error {","sourceCodeStart":270,"sourceCodeEnd":306,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/agent/runtime.go#L270-L306","documentation":"beginRuntimeTurn verifies that the session's entry list actually contains a user entry whose ID matches turn.UserEntryID (via findRuntimeUserAnchor). If no such anchor exists, the turn has no user message to attach to, so beginning it would create an orphaned turn; the kernel rejects it.","triggerScenarios":"Calling beginRuntimeTurn with a turn whose UserEntryID references a user entry that does not exist in session.json — a stale/deleted entry ID, an ID from a different session, or an entry removed by regeneration/rollback.","commonSituations":"Client caching entry IDs across a session regeneration or history rewrite; passing a turn built against another session's entries; an editing operation that removed the user message the turn was derived from.","solutions":["Re-read the session state and use the current user entry ID when constructing the turn","Confirm the turn belongs to this session; cross-session entry IDs will never match","If regeneration removed the entry, recreate the user message first (or use the regenerate/recovery path) and then begin the turn with the new entry ID"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const session = loadSession(sessionID);\nif (!session.entries.some(e => e.id === turn.userEntryID && e.type === \"user\")) throw new Error(`user entry ${turn.userEntryID} not in session; re-read session state`);","typeGuard":null,"tryCatchPattern":"if err := beginRuntimeTurn(sessionID, turn); err != nil {\n  if strings.Contains(err.Error(), \"user entry not found\") {\n    // refresh session state, rebuild the turn against the current user entry, retry once\n  }\n}","preventionTips":["Re-read session state immediately before building a turn; never cache user entry IDs across regeneration or rollback","Verify the turn and its user entry come from the same session","After any history-editing operation, rebuild dependent turns from the updated entry list"],"tags":["agent","turn","entry-not-found"],"backgroundTag":"entity-not-found","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}