{"record":{"id":"e6e624581e52d6a5","repo":"Hmbown/CodeWhale","slug":"runtime-store-path-must-be-a-directory","errorCode":null,"errorMessage":"Runtime store path must be a directory: {}","messagePattern":"Runtime store path must be a directory: (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/runtime_threads.rs","lineNumber":9038,"sourceCode":"        .set_len(original_len)\n        .context(\"Failed to roll back Runtime event\")?;\n    rollback_file\n        .sync_all()\n        .context(\"Failed to sync Runtime event rollback\")\n}\n\nfn reject_symlinked_store_dir(path: &Path) -> Result<()> {\n    let Ok(metadata) = fs::symlink_metadata(path) else {\n        return Ok(());\n    };\n    if metadata.file_type().is_symlink() {\n        bail!(\n            \"Runtime store directory must not be a symlink: {}\",\n            path.display()\n        );\n    }\n    if !metadata.is_dir() {\n        bail!(\"Runtime store path must be a directory: {}\", path.display());\n    }\n    Ok(())\n}\n\nfn ensure_runtime_store_dir(path: &Path) -> Result<()> {\n    fs::create_dir_all(path).with_context(|| format!(\"Failed to create {}\", path.display()))?;\n    reject_symlinked_store_dir(path)\n}\n\nfn read_complete_event(\n    reader: &mut impl BufRead,\n    path: &Path,\n) -> Result<Option<RuntimeEventRecord>> {\n    Ok(read_complete_event_bytes(reader, path)?.map(|(event, _)| event))\n}\n\nfn read_complete_event_bytes(\n    reader: &mut impl BufRead,","sourceCodeStart":9020,"sourceCodeEnd":9056,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/runtime_threads.rs#L9020-L9056","documentation":"After create_dir_all and the symlink check, ensure_runtime_store_dir/reject_symlinked_store_dir found the store path exists but is not a directory (crates/tui/src/runtime_threads.rs:9038) — typically a regular file occupying the name where the directory must live, so directory creation cannot succeed and subsequent file writes would fail.","triggerScenarios":"Store root misconfigured to a path that is an existing file (e.g. pointing at a config file); an earlier partial setup left a file where the directory belongs; a typo maps the store root onto a file like 'runtime.json'","commonSituations":"Copy-pasted config where a file path was pasted into a directory option; cleanup scripts that replaced dirs with marker files; case-insensitive filesystems colliding names.","solutions":["Remove or rename the conflicting file so a real directory can be created","Choose a different, directory-shaped store root path","Restore from backup if the file was a legitimate store artifact misplaced","Add a startup check that the configured root either does not exist or is a directory"],"exampleFix":"# before\n$ ls -la ~/.codewhale\n-rw-r--r--  1 me  me  4096 runtime   # file blocking the dir\n\n# after\n$ mv ~/.codewhale/runtime ~/.codewhale/runtime.bak\n$ mkdir -p ~/.codewhale/runtime","handlingStrategy":"validation","validationCode":"// Ensure the configured root is absent or a directory before starting.\nif let Ok(md) = std::fs::symlink_metadata(&root) {\n    if !md.is_dir() {\n        return Err(anyhow::anyhow!(\"store root is not a directory: {}\", root.display()));\n    }\n}","typeGuard":"fn is_directory_or_missing(path: &Path) -> bool {\n    std::fs::symlink_metadata(path)\n        .map(|md| md.is_dir())\n        .unwrap_or(true)\n}","tryCatchPattern":"match ensure_runtime_store_dir(&root) {\n    Ok(()) => {}\n    Err(err) if err.to_string().contains(\"must be a directory\") => {\n        // Move the conflicting file aside and let creation proceed.\n        std::fs::rename(&root, root.with_extension(\"conflict\"))?;\n        ensure_runtime_store_dir(&root)?;\n    }\n    Err(err) => return Err(err),\n}","preventionTips":["Use dedicated directory paths for directory-valued config; never paste file paths","Validate config shape (dir vs file) at startup with a doctor command","Watch for case-insensitive filesystem collisions between file and dir names","Clean partial setups before reinitializing the store"],"tags":["rust","filesystem","store","configuration","startup"],"backgroundTag":"path-is-not-directory","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}