Hmbown/CodeWhale · error

workspace path cannot contain '..' components

Error message

workspace path cannot contain '..' components

What it means

checked_workspace_path rejects workspace paths containing any ParentDir ('..') component. Because the workspace root itself would be ambiguous after traversal, any '..' anywhere in the input is refused before canonicalization, regardless of whether normalization would resolve it back inside.

Source

Thrown at crates/tui/src/mcp.rs:3839

fn workspace_allows_project_mcp_config(workspace: &Path) -> bool {
    crate::config::is_workspace_trusted(workspace)
}

fn checked_workspace_mcp_config_path(workspace: &Path) -> Result<PathBuf> {
    Ok(checked_workspace_path(workspace)?
        .join(".codewhale")
        .join("mcp.json"))
}

fn checked_workspace_path(workspace: &Path) -> Result<PathBuf> {
    if workspace.as_os_str().is_empty() {
        anyhow::bail!("workspace path cannot be empty");
    }
    if workspace
        .components()
        .any(|component| matches!(component, Component::ParentDir))
    {
        anyhow::bail!("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 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 workspace {}", workspace.display()))
        }
    }
}

View on GitHub (pinned to 8880682c63)

Solutions

  1. Canonicalize the workspace path (std::fs::canonicalize) before passing it in
  2. Normalize away '..' components at the boundary where user input is accepted
  3. Reject '..' early in CLI validation with a clearer message

Example fix

// before
let ws = std::path::PathBuf::from("/home/me/proj/../proj2");
let cfg = checked_workspace_mcp_config_path(&ws)?;

// after
let ws = std::fs::canonicalize("/home/me/proj/../proj2")?;
let cfg = checked_workspace_mcp_config_path(&ws)?;
Defensive patterns

Strategy: validation

Validate before calling

// Canonicalize user-supplied workspaces before use:
let workspace = std::fs::canonicalize(&raw_workspace)
    .unwrap_or_else(|_| normalize_path_components(&raw_workspace));
anyhow::ensure!(!workspace.components().any(|c| matches!(c, std::path::Component::ParentDir)), "workspace contains '..'");

Type guard

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

Prevention

When it happens

Trigger: Passing a workspace like /home/me/proj/../proj2 or a relative ../repo into project MCP config resolution.

Common situations: Shell scripts composing paths with '..'; user-supplied --workspace arguments; config files storing unnormalized paths.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/00fabcb95e11ebf4. Report an issue: GitHub.