{"record":{"id":"1ba0de408c7a48a9","repo":"Hmbown/CodeWhale","slug":"invalid-session-id-for-memory-reconcile","errorCode":null,"errorMessage":"invalid session id for memory reconcile","messagePattern":"invalid session id for memory reconcile","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/native_memory.rs","lineNumber":376,"sourceCode":"                Some(prepared.packet.text)\n            }),\n            Err(_) => self.prompt_block(workspace, max_entries, max_chars),\n        }\n    }\n    /// Run the session-start boundary for `session_id`. The hook plan maps it\n    /// to ReconcilePendingOperations, realized here as detection — contexts\n    /// this session prepared but never saw dispatch-acknowledged — because the\n    /// store owns the receipts and only a host can replay them. Completion is\n    /// recorded durably, so a restarted session reconciles once.\n    /// Returns the number of interrupted contexts found.\n    pub fn session_start(&self, workspace: &Path, session_id: &str) -> Result<usize> {\n        if session_id.is_empty()\n            || session_id.len() > 128\n            || !session_id\n                .bytes()\n                .all(|b| b.is_ascii_alphanumeric() || b\"_-.:\".contains(&b))\n        {\n            bail!(\"invalid session id for memory reconcile\");\n        }\n        let (store, access, context_scope) = self.session_binding(workspace, session_id)?;\n        let snapshot = workspace::snapshot(workspace, store.dependency_paths(&access)?)?;\n        let event = HookEvent {\n            id: format!(\"session-start:{session_id}\"),\n            boundary: Boundary::SessionStart,\n            trace_id: session_id.to_owned(),\n            sequence: 0,\n            observed_at: store.timestamp(),\n            explicit_user_request: false,\n            success: None,\n        };\n        let plan = hooks::plan(\n            &HookPolicy {\n                enabled: true,\n                auto_candidates: false,\n                recall_on_task: true,\n            },","sourceCodeStart":358,"sourceCodeEnd":394,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/native_memory.rs#L358-L394","documentation":"native_memory session_start() validates the session id before binding memory state to it: it must be non-empty, at most 128 bytes, and contain only ASCII alphanumerics plus _ - . :. Anything else is refused so the id is safe as a storage key and event id component.","triggerScenarios":"Calling session_start with an empty string, an id longer than 128 chars, or one containing characters outside [A-Za-z0-9_-.:] — e.g. ids with spaces, slashes, unicode, or a full UUID with braces.","commonSituations":"Passing a raw path or URL as the session id; embedding a display name with spaces; using a generated id with different alphabet (base64 '+' or '/'); forgetting to initialize the id so it's empty.","solutions":["Sanitize the session id to the allowed alphabet before calling session_start.","Generate ids as alphanumeric (or hex/UUID-hyphen form), which passes the check unchanged.","Truncate or hash over-long identifiers to <=128 bytes (e.g. SHA-256 hex).","Ensure the id variable is actually populated before the call."],"exampleFix":"// before\nsession.session_start(workspace, &raw_label)?; // may contain spaces/slashes\n\n// after\nlet id: String = raw_label.chars().map(|c| if c.is_ascii_alphanumeric() || b\"_-.:\".contains(&c as u8) { c } else { '_' }).collect();\nsession.session_start(workspace, &id)?;","handlingStrategy":"validation","validationCode":"fn valid_session_id(id: &str) -> bool {\n    !id.is_empty()\n        && id.len() <= 128\n        && id.bytes().all(|b| b.is_ascii_alphanumeric() || b\"_-.:\".contains(&b))\n}","typeGuard":"fn is_valid_session_id(id: &str) -> bool {\n    !id.is_empty() && id.len() <= 128\n        && id.bytes().all(|b| b.is_ascii_alphanumeric() || b\"_-.:\".contains(&b))\n}","tryCatchPattern":null,"preventionTips":["Generate session ids from a safe alphabet (hex UUIDs qualify).","Never pass paths, URLs, or display strings as session ids.","Sanitize (replace disallowed chars) at the id's point of creation.","Hash or truncate identifiers longer than 128 bytes."],"tags":["memory","session","validation","identifier"],"backgroundTag":"invalid-identifier-format","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T21:17:16.096Z"}