Hmbown/CodeWhale · error · anyhow::Error
Runtime store path must be a directory: {}
Error message
Runtime store path must be a directory: {} What it means
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.
Source
Thrown at crates/tui/src/runtime_threads.rs:9038
.set_len(original_len)
.context("Failed to roll back Runtime event")?;
rollback_file
.sync_all()
.context("Failed to sync Runtime event rollback")
}
fn reject_symlinked_store_dir(path: &Path) -> Result<()> {
let Ok(metadata) = fs::symlink_metadata(path) else {
return Ok(());
};
if metadata.file_type().is_symlink() {
bail!(
"Runtime store directory must not be a symlink: {}",
path.display()
);
}
if !metadata.is_dir() {
bail!("Runtime store path must be a directory: {}", path.display());
}
Ok(())
}
fn ensure_runtime_store_dir(path: &Path) -> Result<()> {
fs::create_dir_all(path).with_context(|| format!("Failed to create {}", path.display()))?;
reject_symlinked_store_dir(path)
}
fn read_complete_event(
reader: &mut impl BufRead,
path: &Path,
) -> Result<Option<RuntimeEventRecord>> {
Ok(read_complete_event_bytes(reader, path)?.map(|(event, _)| event))
}
fn read_complete_event_bytes(
reader: &mut impl BufRead,View on GitHub (pinned to 0c42157ee5)
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
Example fix
# before $ ls -la ~/.codewhale -rw-r--r-- 1 me me 4096 runtime # file blocking the dir # after $ mv ~/.codewhale/runtime ~/.codewhale/runtime.bak $ mkdir -p ~/.codewhale/runtime
Defensive patterns
Strategy: validation
Validate before calling
// Ensure the configured root is absent or a directory before starting.
if let Ok(md) = std::fs::symlink_metadata(&root) {
if !md.is_dir() {
return Err(anyhow::anyhow!("store root is not a directory: {}", root.display()));
}
} Type guard
fn is_directory_or_missing(path: &Path) -> bool {
std::fs::symlink_metadata(path)
.map(|md| md.is_dir())
.unwrap_or(true)
} Try / catch
match ensure_runtime_store_dir(&root) {
Ok(()) => {}
Err(err) if err.to_string().contains("must be a directory") => {
// Move the conflicting file aside and let creation proceed.
std::fs::rename(&root, root.with_extension("conflict"))?;
ensure_runtime_store_dir(&root)?;
}
Err(err) => return Err(err),
} Prevention
- 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
When it happens
Trigger: 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'
Common situations: 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.
Related errors
- Runtime store root cannot be empty
- Runtime store root cannot contain '..' components
- Runtime store file must not be a symlink: {}
- Runtime store directory must not be a symlink: {}
- config path must not be a symlink: {}
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/e6e624581e52d6a5.
Report an issue: GitHub.