Hmbown/CodeWhale · error · anyhow::Error

config path cannot contain '..' components

Error message

config path cannot contain '..' components

What it means

Thrown by normalize_config_file_path when the config path contains at least one '..' (ParentDir) component. This is a deliberate path-traversal guard: the resolved config location must be expressible without parent references, so the normalizer rejects the input before resolving it against the current directory.

Source

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

                    redact_toml_value_for_display_inner(&path, sensitive, child_value),
                );
            }
            toml::Value::Table(redacted)
        }
        _ if sensitive => toml::Value::String("********".to_string()),
        _ => value.clone(),
    }
}

fn normalize_config_file_path(path: PathBuf) -> Result<PathBuf> {
    if path.as_os_str().is_empty() {
        bail!("config path cannot be empty");
    }
    if path
        .components()
        .any(|component| matches!(component, Component::ParentDir))
    {
        bail!("config path cannot contain '..' components");
    }
    if path.file_name().is_none() {
        bail!("config path must include a file name");
    }
    let absolute = if path.is_absolute() {
        path
    } else {
        std::env::current_dir()
            .context("failed to resolve current directory for config path")?
            .join(path)
    };
    let file_name = absolute
        .file_name()
        .map(OsString::from)
        .context("config path must include a file name")?;
    let parent = absolute
        .parent()
        .context("config path must include a parent directory")?;

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Pass an absolute path with no '..' components, e.g. /home/user/shared/codewhale.toml
  2. Or pass a path relative to the current directory that stays inside it, e.g. config/codewhale.toml
  3. Canonicalize the path in your own shell/script first (realpath) and pass the result, which contains no parent components

Example fix

# before
codewhale --config ../shared/codewhale.toml

# after
codewhale --config "$(realpath ../shared/codewhale.toml)"
Defensive patterns

Strategy: validation

Validate before calling

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

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

assert!(traversal_free(Path::new(&flag)), "config path must not contain '..'");

Type guard

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

Prevention

When it happens

Trigger: `--config ../shared/codewhale.toml`, `--config ./releases/../../config.toml`, or any relative path that walks upward. The check runs on the raw components, so the '..' is rejected even when it would lexically cancel out.

Common situations: Keeping a shared config in a parent directory; monorepo setups reaching for ../../team-config.toml; attempting to work around the symlink rejection (error 148) by pointing through '..'; scripts building paths via concat(cwd, '/../x').

Related errors


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