{"record":{"id":"b53aba6d9694a287","repo":"jdx/mise","slug":"uv-workspace-member-pattern-member-must-be-rel","errorCode":null,"errorMessage":"uv workspace member pattern {member:?} must be relative","messagePattern":"uv workspace member pattern (.+?) must be relative","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/task/workspace/uv.rs","lineNumber":294,"sourceCode":"        })\n        .collect()\n}\n\nfn discover_members(\n    pattern_root: &Path,\n    canonical_root: &Path,\n    members: &[String],\n    excludes: &[Pattern],\n    context: &WorkspaceDiscoveryContext,\n) -> Result<BTreeSet<PathBuf>> {\n    let options = match_options();\n    // Avoid canonical Windows roots here because their verbatim `\\\\?\\` prefix\n    // contains a character that glob interprets as a wildcard.\n    let escaped_root = Pattern::escape(&pattern_root.to_string_lossy());\n    let mut roots = BTreeSet::new();\n    for member in members {\n        if Path::new(member).is_absolute() {\n            bail!(\"uv workspace member pattern {member:?} must be relative\");\n        }\n        let pattern = format!(\"{escaped_root}/{member}\");\n        for candidate in glob::glob_with(&pattern, options)\n            .wrap_err_with(|| format!(\"invalid uv workspace member pattern {member:?}\"))?\n        {\n            let candidate = candidate.wrap_err_with(|| {\n                format!(\"failed to evaluate uv workspace member pattern {member:?}\")\n            })?;\n            if !context.is_dir(&candidate) {\n                continue;\n            }\n            let candidate = context.canonicalize(&candidate).wrap_err_with(|| {\n                format!(\n                    \"failed to resolve uv workspace member {}\",\n                    candidate.display()\n                )\n            })?;\n            let relative = relative_root(canonical_root, &candidate)?;","sourceCodeStart":276,"sourceCodeEnd":312,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/task/workspace/uv.rs#L276-L312","documentation":"uv workspace `members` patterns are globbed relative to the workspace root; an absolute path pattern would produce a broken `escaped_root/member` glob and is rejected outright. The check runs before glob expansion in discover_members.","triggerScenarios":"A pyproject.toml `[tool.uv.workspace] members = [\"/abs/path/pkg\"]` (or a Windows drive letter / verbatim `\\\\?\\` path) is expanded by discover_with_context; discover_members bails because Path::is_absolute() is true.","commonSituations":"IDE- or tool-generated member entries that were absolute; copying member lists between machines; Windows users pasting `C:\\...`-style paths into members.","solutions":["Change the member entry to a path relative to the workspace root, e.g. \"packages/*\"","If you need to reference an external directory, use a relative path like \"../shared-lib\" instead of an absolute one","Fix Windows entries to use forward-slash relative paths rather than drive-letter absolute paths"],"exampleFix":"# before\n[tool.uv.workspace]\nmembers = [\"/home/me/proj/packages/api\"]\n\n# after\n[tool.uv.workspace]\nmembers = [\"packages/api\"]","handlingStrategy":"validation","validationCode":"# ensure all uv workspace member patterns are relative\nimport tomllib\nm = tomllib.load(open('pyproject.toml','rb'))\nfor pat in m.get('tool', {}).get('uv', {}).get('workspace', {}).get('members', []):\n    if not pat.startswith(('..', './')) and '/' in pat and pat[0] in '/~':\n        raise SystemExit(f'member pattern {pat!r} must be relative')","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always express workspace members relative to the workspace root","Avoid IDE auto-completion inserting absolute paths","Use globs like packages/* rather than enumerated absolute dirs"],"tags":["uv","python","workspace","glob","config"],"backgroundTag":"invalid-argument-value","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}