Hmbown/CodeWhale · error · anyhow::Error
Runtime store root cannot contain '..' components
Error message
Runtime store root cannot contain '..' components
What it means
checked_runtime_store_root rejects any root containing a ParentDir ("..") component (crates/tui/src/runtime_threads.rs:8863). The guard prevents traversal-style and non-canonical roots; relative roots are instead joined onto the current directory and canonicalized, so no ".." is ever needed.
Source
Thrown at crates/tui/src/runtime_threads.rs:8863
fn panic_payload_message(payload: &(dyn std::any::Any + Send)) -> String {
if let Some(message) = payload.downcast_ref::<&str>() {
(*message).to_string()
} else if let Some(message) = payload.downcast_ref::<String>() {
message.clone()
} else {
"unknown panic payload".to_string()
}
}
fn checked_runtime_store_root(root: PathBuf) -> Result<PathBuf> {
if root.as_os_str().is_empty() {
bail!("Runtime store root cannot be empty");
}
if root
.components()
.any(|component| matches!(component, Component::ParentDir))
{
bail!("Runtime store root cannot contain '..' components");
}
let absolute = if root.is_absolute() {
root
} else {
std::env::current_dir()
.context("failed to resolve current directory for runtime store")?
.join(root)
};
match absolute.canonicalize() {
Ok(path) => Ok(path),
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
Ok(normalize_path_components(&absolute))
}
Err(err) => Err(err).with_context(|| {
format!(
"Failed to resolve runtime store root {}",
absolute.display()
)View on GitHub (pinned to 0c42157ee5)
Solutions
- Use an absolute, canonical path for the store root
- Resolve the path first (fs::canonicalize, or a normalizing join) so no ParentDir components remain
- Point the store root directly at the target directory instead of escaping with ".."
- Validate configuration paths at startup with the same component check
Example fix
// before
let root = PathBuf::from("../../shared/codewhale-store");
// after
let root = fs::canonicalize("../../shared/codewhale-store")
.context("store root must exist")?; // absolute, no ParentDir components Defensive patterns
Strategy: validation
Validate before calling
use std::path::{Component, Path};
fn has_parent_component(root: &Path) -> bool {
root.components().any(|c| matches!(c, Component::ParentDir))
}
let root = if has_parent_component(&root) {
fs::canonicalize(&root).context("resolve store root")? // removes '..'
} else { root }; Type guard
fn is_safe_store_root(root: &Path) -> bool {
!root.as_os_str().is_empty()
&& !root.components().any(|c| matches!(c, Component::ParentDir))
} Try / catch
match RuntimeStore::open(root) {
Ok(store) => store,
Err(err) if err.to_string().contains("cannot contain '..'") => {
let canonical = fs::canonicalize(&root)
.context("store root must exist to be canonicalized")?;
RuntimeStore::open(canonical)?
}
Err(err) => return Err(err),
} Prevention
- Prefer absolute, canonical store roots in config
- Never assemble store paths by raw string concatenation; use Path::join and normalize
- Reject '..' in user-supplied paths at the input boundary, not at store open
- Validate paths once at startup with the same component rule
When it happens
Trigger: Configuring the store root as "../../shared/state" or "data/../store"; building the path by string concatenation that leaves ".." fragments; paths written for one machine layout reused on another
Common situations: Shared dotfiles with machine-specific relative escapes; monorepo configs pointing outside the tree with ".."; scripts joining user input without normalization.
Related errors
- Runtime store root cannot be empty
- Runtime store file must not be a symlink: {}
- Runtime store directory must not be a symlink: {}
- Runtime store path must be a directory: {}
- skill version marker should have a parent directory
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/e83dd36d6ade926a.
Report an issue: GitHub.