{"record":{"id":"15c95dce9a9d96a7","repo":"siyuan-note/siyuan","slug":"invalid-session-id","errorCode":null,"errorMessage":"invalid session id","messagePattern":"invalid session id","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/agent/runtime.go","lineNumber":102,"sourceCode":"\tif permissionMode, _ := session[\"permissionMode\"].(string); permissionMode != \"\" {\n\t\tif !validAgentPermissionMode(permissionMode) {\n\t\t\treturn \"\", fmt.Errorf(\"invalid agent permission mode\")\n\t\t}\n\t\treturn permissionMode, nil\n\t}\n\tif alwaysAllow, _ := session[\"alwaysAllow\"].(bool); alwaysAllow {\n\t\treturn AgentPermissionAllowSession, nil\n\t}\n\treturn AgentPermissionConfirm, nil\n}\n\nfunc registerSessionPermissionController(sessionID string) (*sessionPermissionController, error) {\n\tcontroller := &sessionPermissionController{}\n\tif sessionID == \"\" {\n\t\treturn controller, nil\n\t}\n\tif !isValidSessionID(sessionID) {\n\t\treturn nil, fmt.Errorf(\"invalid session id\")\n\t}\n\tlock := sessionLock(sessionID)\n\tlock.Lock()\n\tdefer lock.Unlock()\n\tmode, err := resolveSessionPermissionModeLocked(sessionID, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcontroller.allowSession.Store(mode == AgentPermissionAllowSession)\n\tsessionPermissionControllers.Store(sessionID, controller)\n\treturn controller, nil\n}\n\nfunc unregisterSessionPermissionController(sessionID string, controller *sessionPermissionController) {\n\tif sessionID == \"\" || controller == nil {\n\t\treturn\n\t}\n\tsessionPermissionControllers.CompareAndDelete(sessionID, controller)","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/agent/runtime.go#L84-L120","documentation":"registerSessionPermissionController validates the session ID format before locking session state. Session IDs must match the SiYuan node-ID pattern (ast.IsNodeIDPattern); an empty ID returns a no-op controller, but a non-empty malformed ID is rejected with this error.","triggerScenarios":"Calling registerSessionPermissionController (directly or via session setup paths) with a hand-made or truncated ID such as 'abc', a filename stem without the full node-ID format, or an ID containing invalid characters.","commonSituations":"Custom tooling constructing session IDs instead of using IDs issued by the agent runtime; IDs copied from paths/URLs and mangled; tests passing fake IDs.","solutions":["Use the session ID exactly as issued by the agent runtime (a valid SiYuan node ID, e.g. '20240101120000-abcdefgh') rather than a custom string","Verify the ID matches the node-ID pattern: 14 digits timestamp, hyphen, then alphanumeric suffix","Check for truncation or URL-encoding artifacts when passing IDs between systems"],"exampleFix":"// before\nregisterSessionPermissionController(\"session-1\")\n// after\nregisterSessionPermissionController(\"20240918103000-1a2b3c4\")","handlingStrategy":"validation","validationCode":"if sessionID != \"\" && !ast.IsNodeIDPattern(sessionID) {\n    return fmt.Errorf(\"session id %q is not a valid node ID\", sessionID)\n}","typeGuard":"func isNodeID(s string) bool { return ast.IsNodeIDPattern(s) }","tryCatchPattern":"controller, err := registerSessionPermissionController(id)\nif err != nil { /* reject the ID before touching session state */ }","preventionTips":["Always obtain session IDs from the runtime, never construct them by hand","Sanitize IDs taken from paths or URLs before passing them into agent APIs","Add a node-ID-pattern check at the boundary of any external input"],"tags":["go","agent","sessions","validation"],"backgroundTag":"invalid-identifier-format","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"}