{"record":{"id":"bb4fffbb9546c72a","repo":"Hmbown/CodeWhale","slug":"config-path-cannot-be-empty","errorCode":null,"errorMessage":"config path cannot be empty","messagePattern":"config path cannot be empty","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/config/src/lib.rs","lineNumber":6613,"sourceCode":"                    child_key.clone()\n                } else {\n                    format!(\"{key}.{child_key}\")\n                };\n                redacted.insert(\n                    child_key.clone(),\n                    redact_toml_value_for_display_inner(&path, sensitive, child_value),\n                );\n            }\n            toml::Value::Table(redacted)\n        }\n        _ if sensitive => toml::Value::String(\"********\".to_string()),\n        _ => value.clone(),\n    }\n}\n\nfn normalize_config_file_path(path: PathBuf) -> Result<PathBuf> {\n    if path.as_os_str().is_empty() {\n        bail!(\"config path cannot be empty\");\n    }\n    if path\n        .components()\n        .any(|component| matches!(component, Component::ParentDir))\n    {\n        bail!(\"config path cannot contain '..' components\");\n    }\n    if path.file_name().is_none() {\n        bail!(\"config path must include a file name\");\n    }\n    let absolute = if path.is_absolute() {\n        path\n    } else {\n        std::env::current_dir()\n            .context(\"failed to resolve current directory for config path\")?\n            .join(path)\n    };\n    let file_name = absolute","sourceCodeStart":6595,"sourceCodeEnd":6631,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/config/src/lib.rs#L6595-L6631","documentation":"Thrown by normalize_config_file_path when the config path is the empty string. The normalizer validates shape (non-empty, no '..', has a file name) before resolving the path, and an empty path fails the first check rather than being treated as 'use the default location'.","triggerScenarios":"Passing an explicitly empty --config argument, e.g. `--config \"\"`, or building the path from an empty variable/Option default (PathBuf::from(opt.unwrap_or_default())) so the empty value reaches the normalizer instead of falling back to discovery.","commonSituations":"Shell scripts passing `--config $CFG` with CFG unset or empty; CI matrices where one axis leaves the config var blank; programmatic callers converting an Option<String> into \"\" instead of skipping the override.","solutions":["Omit the --config flag entirely to use default config discovery instead of passing an empty string","Fix the source variable so it holds a real path: CFG=\"${CFG:-$HOME/.codewhale/codewhale.toml}\"","In code, only call the API when the path is present: map the Option to Result with a clear 'config path required' message"],"exampleFix":"// before\nlet path = normalize_config_file_path(PathBuf::from(cfg_flag.unwrap_or_default()))?;\n\n// after\nlet path = normalize_config_file_path(PathBuf::from(cfg_flag.context(\"config path required\")?))?;","handlingStrategy":"validation","validationCode":"if let Some(cfg) = &cfg_flag {\n    anyhow::ensure!(!cfg.is_empty(), \"config path must not be empty\");\n    let normalized = normalize_config_file_path(PathBuf::from(cfg))?;\n    // use normalized\n} else {\n    // default discovery path\n}","typeGuard":null,"tryCatchPattern":"let path = match normalize_config_file_path(candidate) {\n    Ok(p) => p,\n    Err(err) if err.to_string().contains(\"config path cannot be empty\") => {\n        anyhow::bail!(\"no config path given; pass --config <file> or omit the flag\");\n    }\n    Err(err) => return Err(err),\n};","preventionTips":["Treat an empty --config value as 'unset' at your CLI boundary (filter empty strings)","Use ${VAR:-default} in shell instead of passing possibly-empty variables","Never unwrap_or_default() an Option<String> path into a PathBuf that reaches normalizers"],"tags":["rust","config","path","validation"],"backgroundTag":"invalid-file-path","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}