Hmbown/CodeWhale · error

Runtime store root cannot contain '..' components

Error message

Runtime store root cannot contain '..' components

What it means

The runtime store root must not contain '..' parent-directory components; such paths can escape the intended store location and are rejected as a path-traversal guard. After this check the root is resolved to an absolute path.

Solutions

  1. Provide a canonical absolute path without '..' components
  2. Canonicalize/normalize the intended directory (e.g. std::fs::canonicalize or path clean-up) before passing it
  3. Never interpolate untrusted path segments into the store root

Example fix

// before
let root = PathBuf::from("/var/lib/../tmp/store");
// after
let root = std::fs::canonicalize("/var/tmp/store")?;
Defensive patterns

Strategy: validation

Validate before calling

fn has_parent_dir(p: &Path) -> bool {
    p.components().any(|c| matches!(c, std::path::Component::ParentDir))
}

Type guard

fn safe_root(p: PathBuf) -> Option<PathBuf> {
    (!p.components().any(|c| matches!(c, std::path::Component::ParentDir))).then_some(p)
}

Try / catch

let root = std::fs::canonicalize(user_path)
    .map_err(|e| anyhow!("invalid store root: {e}"))?; // canonicalize removes '..'

Prevention

When it happens

Trigger: Configuring a store root like /var/data/../etc/store or ../store, or building a path by joining user-supplied segments containing '..'.

Common situations: Relative default paths that include '..'; users pointing the store at a sibling directory with ../; untrusted input interpolated into the store path.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/e83dd36d6ade926a. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/runtime_threads.rs:13695

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 73e0f67d83)