Hmbown/CodeWhale · error · anyhow::Error

project workspace path cannot contain '..' components

Error message

project workspace path cannot contain '..' components

What it means

Thrown by normalize_project_workspace when the workspace path contains a '..' (ParentDir) component. This is the same anti-traversal guard as the config path normalizer, applied to lane/project workspace roots; the input must be expressible without parent references before canonicalization is attempted.

Source

Thrown at crates/config/src/lib.rs:6660

            return Err(err).with_context(|| {
                format!("failed to resolve config directory {}", parent.display())
            });
        }
    };
    let normalized = parent.join(file_name);
    reject_path_symlink(&normalized)?;
    Ok(normalized)
}

fn normalize_project_workspace(workspace: &Path) -> Result<PathBuf> {
    if workspace.as_os_str().is_empty() {
        bail!("project workspace path cannot be empty");
    }
    if workspace
        .components()
        .any(|component| matches!(component, Component::ParentDir))
    {
        bail!("project workspace path cannot contain '..' components");
    }
    let absolute = if workspace.is_absolute() {
        workspace.to_path_buf()
    } else {
        std::env::current_dir()
            .context("failed to resolve current directory for project workspace")?
            .join(workspace)
    };
    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 project workspace {}",
                workspace.display()
            )

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Pass an absolute, '..'-free path to the workspace (pwd-realpath it first if needed)
  2. Use a path relative to the current directory that descends only, e.g. worktrees/feature-x
  3. Generate paths with realpath/CanonPath in your launcher so they never contain '..'

Example fix

# before
workspace = "../repo"

# after
workspace = "/home/user/repo"
Defensive patterns

Strategy: validation

Validate before calling

use std::path::{Component, Path};

anyhow::ensure!(
    !workspace.components().any(|c| matches!(c, Component::ParentDir)),
    "workspace path must not contain '..'"
);

Type guard

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

Prevention

When it happens

Trigger: workspace = "../repo", "../../team/worktree", or any relative path walking upward from the current directory. The components check runs before the canonicalize/fallback step, so even a lexically-cancelling '..' is rejected.

Common situations: Monorepo scripts addressing sibling worktrees via ../; CI jobs checking out to nested dirs and passing ../../workspace; attempts to escape a sandbox root by '..'.

Related errors


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