{"record":{"id":"2edb24340f3045cf","repo":"Hmbown/CodeWhale","slug":"session-id-id-collides-with-a-reserved-sessions-file","errorCode":null,"errorMessage":"Session id '{id}' collides with a reserved sessions file","messagePattern":"Session id '(.+?)' collides with a reserved sessions file","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/session_manager.rs","lineNumber":1283,"sourceCode":"    fn validated_session_id<'a>(&self, id: &'a str) -> std::io::Result<&'a str> {\n        let trimmed = id.trim();\n        if trimmed.is_empty() {\n            return Err(std::io::Error::new(\n                std::io::ErrorKind::InvalidInput,\n                \"Session id cannot be empty\",\n            ));\n        }\n        if !trimmed\n            .chars()\n            .all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '_')\n        {\n            return Err(std::io::Error::new(\n                std::io::ErrorKind::InvalidInput,\n                format!(\"Invalid session id '{id}'\"),\n            ));\n        }\n        if trimmed == SESSION_BOOT_OWNERS_STEM {\n            return Err(std::io::Error::new(\n                std::io::ErrorKind::InvalidInput,\n                format!(\"Session id '{trimmed}' collides with a reserved sessions file\"),\n            ));\n        }\n        Ok(trimmed)\n    }\n\n    fn validated_session_path(&self, id: &str) -> std::io::Result<PathBuf> {\n        let trimmed = self.validated_session_id(id)?;\n        Ok(self.sessions_dir.join(format!(\"{trimmed}.json\")))\n    }\n\n    fn checkpoints_dir(&self) -> PathBuf {\n        self.sessions_dir.join(\"checkpoints\")\n    }\n\n    fn session_goals_dir(&self) -> PathBuf {\n        self.sessions_dir.join(SESSION_GOALS_DIR)","sourceCodeStart":1265,"sourceCodeEnd":1301,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/session_manager.rs#L1265-L1301","documentation":"After character validation, validated_session_id rejects an id equal to SESSION_BOOT_OWNERS_STEM, the reserved stem of the sessions boot-owners file, with 'Session id ... collides with a reserved sessions file'. Preventing this collision stops a per-session file from overwriting the manager's own bookkeeping file in the sessions directory.","triggerScenarios":"Calling validated_session_id with an id that trims exactly to the reserved boot-owners stem constant.","commonSituations":"A user names a session after the reserved file stem; a foreign /load file or imported session carries that id; tests or scripts hardcode the reserved name as a fixture id.","solutions":["Choose a different session id that does not match the reserved boot-owners stem","Rename the imported/foreign session before loading it into the manager","If the id must be preserved, prefix or suffix it (e.g. 'my-') so it no longer equals the reserved stem"],"exampleFix":"// before\nmanager.resume(&\"boot-owners\")?; // reserved stem\n// after\nmanager.resume(&\"boot-owners-backup\")?;","handlingStrategy":"validation","validationCode":"if id.trim() == SESSION_BOOT_OWNERS_STEM { return Err(anyhow!(\"id is reserved\")); }","typeGuard":null,"tryCatchPattern":"match manager.checkpoint_path(&id) {\n    Ok(p) => use(p),\n    Err(e) if e.to_string().contains(\"reserved sessions file\") => eprintln!(\"'{}' is reserved; pick another name\", id),\n    Err(e) => return Err(e.into()),\n}","preventionTips":["Never use internal file stems as session ids in scripts or tests fixtures","Add the reserved-stem check to any importer that accepts foreign session ids","Auto-suffix colliding ids at ingestion time instead of surfacing the error to users"],"tags":["validation","session-id","reserved-name","rust"],"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-22T11:17:16.035Z"}