{"record":{"id":"d5a7f90a633f1797","repo":"jdx/mise","slug":"workspace-path-path-is-absolute-paths-must-be","errorCode":null,"errorMessage":"workspace path {path:?} is absolute; paths must be workspace-relative","messagePattern":"workspace path (.+?) is absolute; paths must be workspace-relative","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/task/workspace.rs","lineNumber":1222,"sourceCode":"                    );\n                }\n            }\n            Component::RootDir | Component::Prefix(_) => {\n                bail!(\n                    \"workspace project {id:?} has absolute root {root:?}; roots must be workspace-relative\"\n                );\n            }\n        }\n    }\n    if normalized.as_os_str().is_empty() {\n        normalized.push(\".\");\n    }\n    Ok(normalized)\n}\n\nfn normalize_workspace_path(path: &Path) -> Result<PathBuf> {\n    if path.is_absolute() {\n        bail!(\"workspace path {path:?} is absolute; paths must be workspace-relative\");\n    }\n\n    let mut normalized = PathBuf::new();\n    for component in path.components() {\n        match component {\n            Component::CurDir => {}\n            Component::Normal(component) => normalized.push(component),\n            Component::ParentDir => {\n                if !normalized.pop() {\n                    bail!(\"workspace path {path:?} escapes the workspace root\");\n                }\n            }\n            Component::RootDir | Component::Prefix(_) => {\n                bail!(\"workspace path {path:?} is absolute; paths must be workspace-relative\");\n            }\n        }\n    }\n    if normalized.as_os_str().is_empty() {","sourceCodeStart":1204,"sourceCodeEnd":1240,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/task/workspace.rs#L1204-L1240","documentation":"normalize_workspace_path validates general workspace-relative paths (used for workspace files/patterns). Absolute paths are rejected because workspace paths are always resolved against the workspace root; an absolute value would bypass that anchoring, so mise throws this error.","triggerScenarios":"Passing a Path like \"/etc/foo\" or \"C:\\\\foo\" to a workspace path field (e.g. include/exclude/file lists) that flows through normalize_workspace_path.","commonSituations":"Absolute paths produced by tooling or environment expansion ending up in workspace config path lists; copy-pasting absolute paths from logs.","solutions":["Rewrite the path relative to the workspace root","Compute the relative path from the workspace root programmatically (e.g. pathdiff) before writing config","Check that env-var or template expansion in the config is not injecting absolute paths"],"exampleFix":"# before\nworkspace_files = [\"/home/me/proj/mise.toml\"]\n# after\nworkspace_files = [\"mise.toml\"]","handlingStrategy":"validation","validationCode":"fn ensure_relative_workspace_path(p: &std::path::Path) -> Result<(), String> {\n    if p.is_absolute() {\n        return Err(format!(\"workspace path {p:?} must be workspace-relative\"));\n    }\n    Ok(())\n}","typeGuard":"let rel = |p: &std::path::Path| !p.is_absolute();","tryCatchPattern":"if let Err(e) = normalize_workspace_path(&p) {\n    if e.to_string().contains(\"is absolute\") {\n        let rel = p.strip_prefix(&ws_root).unwrap_or(&p);\n        eprintln!(\"use {rel:?} instead\");\n    }\n}","preventionTips":["Compute config paths relative to the workspace root before writing them","Check template/env expansion in config for absolute-path leakage","Strip the workspace base from any path sourced from logs or external tooling"],"tags":["workspace","config","path"],"backgroundTag":"invalid-config-value","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}