{"record":{"id":"ebc97006dc3e0770","repo":"Hmbown/CodeWhale","slug":"session-id-collides-with-a-reserved-checkpoint-file","errorCode":null,"errorMessage":"Session id '{}' collides with a reserved checkpoint file","messagePattern":"Session id '(.+?)' collides with a reserved checkpoint file","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/session_manager.rs","lineNumber":1368,"sourceCode":"            Err(error) => return Err(error),\n        };\n        if metadata.file_type().is_symlink() || !metadata.is_file() {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                format!(\"Session goal {} must be a regular file\", path.display()),\n            ));\n        }\n        Ok(true)\n    }\n\n    fn validated_checkpoint_path(&self, session_id: &str) -> std::io::Result<PathBuf> {\n        let trimmed = self.validated_session_id(session_id)?;\n        // Reserved file names inside `checkpoints/` must never collide with a\n        // per-session checkpoint file.\n        if format!(\"{trimmed}.json\") == LEGACY_CHECKPOINT_FILE\n            || format!(\"{trimmed}.json\") == OFFLINE_QUEUE_FILE\n        {\n            return Err(std::io::Error::new(\n                std::io::ErrorKind::InvalidInput,\n                format!(\"Session id '{trimmed}' collides with a reserved checkpoint file\"),\n            ));\n        }\n        Ok(self.checkpoints_dir().join(format!(\"{trimmed}.json\")))\n    }\n\n    /// Create a new `SessionManager` with the specified sessions directory\n    pub fn new(sessions_dir: PathBuf) -> std::io::Result<Self> {\n        let sessions_dir = normalize_managed_dir(sessions_dir)?;\n        // Ensure the sessions directory exists\n        fs::create_dir_all(&sessions_dir)?;\n        Ok(Self {\n            sessions_dir,\n            retention_in_progress: AtomicBool::new(false),\n        })\n    }\n","sourceCodeStart":1350,"sourceCodeEnd":1386,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/session_manager.rs#L1350-L1386","documentation":"checkpoint_path validates the session id and then additionally rejects ids whose '<id>.json' equals LEGACY_CHECKPOINT_FILE or OFFLINE_QUEUE_FILE, with 'Session id ... collides with a reserved checkpoint file'. This prevents a per-session checkpoint from overwriting the legacy checkpoint or offline-queue files that live in the same checkpoints/ directory.","triggerScenarios":"Calling checkpoint_path (or APIs that derive checkpoint paths from a session id) with an id like the legacy checkpoint stem or the offline-queue stem — e.g. id 'offline-queue' when OFFLINE_QUEUE_FILE is 'offline-queue.json'.","commonSituations":"Users naming sessions after the reserved stems seen in the checkpoints directory listing; imported or hand-copied session files using legacy names; automated id generation colliding with the legacy file constants.","solutions":["Pick a session id whose .json name differs from LEGACY_CHECKPOINT_FILE and OFFLINE_QUEUE_FILE","Rename or migrate the foreign/imported session before loading","Add a suffix/prefix to generated ids (e.g. session-<uuid>) so they cannot equal reserved stems"],"exampleFix":"// before\nlet id = \"offline-queue\"; // collides with OFFLINE_QUEUE_FILE\n// after\nlet id = \"offline-queue-session\";","handlingStrategy":"validation","validationCode":"let name = format!(\"{}.json\", id.trim());\nif name == LEGACY_CHECKPOINT_FILE || name == OFFLINE_QUEUE_FILE { return Err(anyhow!(\"id collides with reserved checkpoint file\")); }","typeGuard":"fn safe_checkpoint_id(id: &str) -> bool {\n    let t = id.trim();\n    !t.is_empty()\n        && t.chars().all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '_')\n        && format!(\"{t}.json\") != \"checkpoint.json\"\n        && format!(\"{t}.json\") != \"offline-queue.json\"\n}","tryCatchPattern":"match manager.checkpoint_path(&id) {\n    Ok(p) => use(p),\n    Err(e) if e.to_string().contains(\"reserved checkpoint file\") => eprintln!(\"Session id '{}' uses a reserved file name; rename it\", id),\n    Err(e) => return Err(e.into()),\n}","preventionTips":["Prefix generated ids (e.g. 'session-') so they can never equal reserved stems","Check the checkpoints/ directory listing before importing sessions with hand-picked ids","Keep an exclusion list in import tooling mirroring the reserved-file constants"],"tags":["validation","session-id","reserved-name","checkpoints"],"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"}