{"record":{"id":"89e0c0e8ea399221","repo":"siyuan-note/siyuan","slug":"invalid-agent-runtime-turn","errorCode":null,"errorMessage":"invalid agent runtime turn","messagePattern":"invalid agent runtime turn","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/agent/runtime.go","lineNumber":257,"sourceCode":"\truntime.SchemaVersion = 1\n\truntime.SessionID = sessionID\n\truntime.Revision++\n\tdata, err := gulu.JSON.MarshalIndentJSON(runtime, \"\", \"\\t\")\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn filelock.WriteFile(runtimePath(sessionID), data)\n}\n\nfunc beginRuntimeTurn(sessionID string, turn *agentRuntimeTurn) error {\n\tif sessionID == \"\" || turn == nil {\n\t\treturn nil\n\t}\n\tif !isValidSessionID(sessionID) {\n\t\treturn fmt.Errorf(\"invalid session id\")\n\t}\n\tif turn.TurnID == \"\" || turn.State != \"running\" {\n\t\treturn fmt.Errorf(\"invalid agent runtime turn\")\n\t}\n\tlock := sessionLock(sessionID)\n\tlock.Lock()\n\tdefer lock.Unlock()\n\truntime, err := loadRuntimeLocked(sessionID)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif runtime.ActiveTurn != nil && runtime.ActiveTurn.TurnID != turn.TurnID {\n\t\tcommitted, err := isTurnCommittedLocked(sessionID, runtime.ActiveTurn.TurnID)\n\t\tif err != nil {\n\t\t\treturn err\n\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}","sourceCodeStart":239,"sourceCodeEnd":275,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/agent/runtime.go#L239-L275","documentation":"beginRuntimeTurn requires the turn argument to carry a non-empty TurnID and to be in the \"running\" state. This error means the turn passed in is structurally invalid as a turn to begin — it either lacks an identifier or is not entering the running state, so recording it as the session's ActiveTurn would be meaningless.","triggerScenarios":"Calling beginRuntimeTurn with a turn whose TurnID is \"\" or whose State is anything other than \"running\" (e.g. building a finished/interrupted turn and passing it to begin instead of the appropriate completion path).","commonSituations":"Constructing agentRuntimeTurn by hand and forgetting to set TurnID; reusing a completed turn object for a new begin call; a state machine bug that marks the turn finished before beginning it.","solutions":["Set turn.TurnID to a fresh unique identifier before calling beginRuntimeTurn","Ensure turn.State is exactly \"running\" when beginning; handle finished/interrupted turns through their own code paths","Use the public turn-start APIs rather than assembling agentRuntimeTurn manually"],"exampleFix":"// before\nturn := &agentRuntimeTurn{State: \"finished\"}\nbeginRuntimeTurn(sessionID, turn)\n// after\nturn := &agentRuntimeTurn{TurnID: newTurnID(), State: \"running\"}\nbeginRuntimeTurn(sessionID, turn)","handlingStrategy":"validation","validationCode":"if (!turn.turnID) throw new Error(\"turnID is required before beginRuntimeTurn\");\nif (turn.state !== \"running\") throw new Error(`cannot begin a turn in state ${turn.state}`);","typeGuard":"function isBeginnableTurn(t: AgentRuntimeTurn): boolean { return typeof t.turnID === \"string\" && t.turnID !== \"\" && t.state === \"running\"; }","tryCatchPattern":null,"preventionTips":["Generate a fresh TurnID for every new turn and set state to \"running\" before beginning","Route finished/interrupted turns to completion APIs, never back through begin","Construct turns through a single factory function that enforces these invariants"],"tags":["agent","turn","validation"],"backgroundTag":"invalid-argument-value","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"}