{"record":{"id":"0ff973e6f03307fa","repo":"Hmbown/CodeWhale","slug":"project-workspace-path-cannot-be-empty","errorCode":null,"errorMessage":"project workspace path cannot be empty","messagePattern":"project workspace path cannot be empty","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/config/src/lib.rs","lineNumber":6654,"sourceCode":"        .parent()\n        .context(\"config path must include a parent directory\")?;\n    let parent = match parent.canonicalize() {\n        Ok(parent) => parent,\n        Err(err) if err.kind() == std::io::ErrorKind::NotFound => parent.to_path_buf(),\n        Err(err) => {\n            return Err(err).with_context(|| {\n                format!(\"failed to resolve config directory {}\", parent.display())\n            });\n        }\n    };\n    let normalized = parent.join(file_name);\n    reject_path_symlink(&normalized)?;\n    Ok(normalized)\n}\n\nfn normalize_project_workspace(workspace: &Path) -> Result<PathBuf> {\n    if workspace.as_os_str().is_empty() {\n        bail!(\"project workspace path cannot be empty\");\n    }\n    if workspace\n        .components()\n        .any(|component| matches!(component, Component::ParentDir))\n    {\n        bail!(\"project workspace path cannot contain '..' components\");\n    }\n    let absolute = if workspace.is_absolute() {\n        workspace.to_path_buf()\n    } else {\n        std::env::current_dir()\n            .context(\"failed to resolve current directory for project workspace\")?\n            .join(workspace)\n    };\n    match absolute.canonicalize() {\n        Ok(path) => Ok(path),\n        Err(err) if err.kind() == std::io::ErrorKind::NotFound => {\n            Ok(normalize_path_components(&absolute))","sourceCodeStart":6636,"sourceCodeEnd":6672,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/config/src/lib.rs#L6636-L6672","documentation":"Thrown by normalize_project_workspace when the workspace path is the empty string. Like the config path normalizer, it validates shape before resolving: a workspace must be a non-empty path, and empty input is an error rather than a cue to use a default.","triggerScenarios":"Registering a lane/project with workspace set to \"\" — an empty CLI argument, an unset variable expanded to nothing, or an Option<PathBuf> defaulting to PathBuf::new() before reaching the normalizer.","commonSituations":"Automation where the workspace cell in a matrix is blank; wrapper scripts passing \"$WORKSPACE\" before it is assigned; code that converts a missing workspace into an empty PathBuf instead of requiring one.","solutions":["Pass the actual project directory (absolute paths are safest): workspace = \"/repo/my-project\"","Fix the empty variable: WORKSPACE=\"${WORKSPACE:-$PWD}\"","In code, require the workspace before calling the API instead of defaulting it to an empty path"],"exampleFix":"// before\nlet ws = normalize_project_workspace(Path::new(ws_flag.unwrap_or_default()))?;\n\n// after\nlet ws = normalize_project_workspace(Path::new(ws_flag.context(\"workspace required\")?))?;","handlingStrategy":"validation","validationCode":"anyhow::ensure!(!workspace.as_os_str().is_empty(), \"workspace path required\");\nlet normalized = normalize_project_workspace(&workspace)?;","typeGuard":"fn has_workspace(p: &std::path::Path) -> bool {\n    !p.as_os_str().is_empty()\n}","tryCatchPattern":null,"preventionTips":["Make workspace a required argument in your wrappers and fail early with a clear message","Default blank matrix/env cells to $PWD instead of passing them through empty"],"tags":["rust","lane","workspace","path","validation"],"backgroundTag":"invalid-file-path","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}