Hmbown/CodeWhale · error

config path cannot contain '..' components

Error message

config path cannot contain '..' components

What it means

normalize_config_file_path rejects config paths containing '..' components before they are resolved. This prevents path traversal out of the intended config directory and avoids ambiguous resolution. It is a deliberate security/validation guard, not a bug.

Solutions

  1. Use an absolute path with no '..' components
  2. Use a relative path that starts from the intended directory without '..' (e.g. "codewhale/config.toml")
  3. Resolve the '..' yourself (e.g. via std::fs::canonicalize) before passing the path

Example fix

// before
load_config(PathBuf::from("../codewhale/config.toml"))
// after
let path = std::fs::canonicalize("../codewhale/config.toml")?;
load_config(path)
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

fn safe_config_path(p: &str) -> Option<std::path::PathBuf> {
    use std::path::Component;
    let path = std::path::PathBuf::from(p);
    (!path.components().any(|c| matches!(c, Component::ParentDir))).then_some(path)
}

Try / catch

match normalize_config_file_path(path) {
    Ok(p) => p,
    Err(e) if e.to_string().contains("'..' components") => {
        eprintln!("rewrite the path without '..'; got: {}", path.display());
        std::process::exit(2);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Passing a config path such as "/etc/../../home/user/config.toml", "../config.toml", or "a/../config.toml" to the config loader.

Common situations: Users expressing 'the config one level up' with relative paths, scripts templating paths with ../ segments, or symlink-following setups where users expect .. to be normalized silently.

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/0a7a1137bc1fa432. Report an issue: GitHub.

Appendix: source

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

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