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

  1. Use an absolute, canonical path for the store root
  2. Resolve the path first (fs::canonicalize, or a normalizing join) so no ParentDir components remain
  3. Point the store root directly at the target directory instead of escaping with ".."
  4. 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

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


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/e83dd36d6ade926a. Report an issue: GitHub.