jdx/mise · error
Cargo workspace member pattern {member:?} must be relative
Error message
Cargo workspace member pattern {member:?} must be relative What it means
The Cargo workspace provider expands each entry of [workspace] members (and default-members) in the root Cargo.toml as a glob under the workspace root. Entries must be relative patterns: an absolute member path is rejected before globbing because mise composes the pattern as "{root}/{member}" and an absolute member would both break that composition and break portability of the manifest.
Source
Thrown at src/task/workspace/cargo.rs:254
fn discover_members(
pattern_root: &Path,
canonical_root: &Path,
members: &[String],
excludes: &[Pattern],
context: &WorkspaceDiscoveryContext,
) -> Result<BTreeSet<PathBuf>> {
let options = MatchOptions {
case_sensitive: true,
require_literal_separator: true,
require_literal_leading_dot: true,
};
// Use the caller's non-canonical path for globbing. Windows canonical paths
// use a verbatim `\\?\` prefix whose `?` is interpreted as a glob token.
let escaped_root = Pattern::escape(&pattern_root.to_string_lossy());
let mut roots = BTreeSet::new();
for member in members {
if Path::new(member).is_absolute() {
bail!("Cargo workspace member pattern {member:?} must be relative");
}
let pattern = format!("{escaped_root}/{member}");
for candidate in glob::glob_with(&pattern, options)
.wrap_err_with(|| format!("invalid Cargo workspace member pattern {member:?}"))?
{
let candidate = candidate.wrap_err_with(|| {
format!("failed to evaluate Cargo workspace member pattern {member:?}")
})?;
if !context.is_file(&candidate.join(CARGO_TOML)) {
continue;
}
let candidate = context.canonicalize(&candidate).wrap_err_with(|| {
format!(
"failed to resolve Cargo workspace member {}",
candidate.display()
)
})?;
let relative = relative_root(canonical_root, &candidate)?;View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Change the member entry to a root-relative pattern such as "crates/*"
- If the crate lives outside the workspace root, move it inside or relocate the workspace root — absolute members are not supported
- After editing, verify with cargo metadata --no-deps that cargo itself accepts the manifest
Example fix
# before (root Cargo.toml) [workspace] members = ["/home/me/monorepo/crates/*"] # after [workspace] members = ["crates/*"]
Defensive patterns
Strategy: validation
Validate before calling
let manifest: toml::Value = toml::from_str(&std::fs::read_to_string(root.join("Cargo.toml"))?)?;
for member in manifest.get("workspace").and_then(|w| w.get("members")).and_then(|m| m.as_array()).into_iter().flatten().filter_map(|m| m.as_str()) {
if Path::new(member).is_absolute() {
return Err(eyre::eyre!("absolute workspace member {member}; make it root-relative"));
}
} Type guard
fn cargo_members_are_relative(root: &Path) -> bool {
let Ok(text) = std::fs::read_to_string(root.join("Cargo.toml")) else { return true };
toml::from_str::<toml::Value>(&text)
.ok()
.and_then(|v| v.get("workspace").and_then(|w| w.get("members")).and_then(|m| m.as_array()).cloned())
.map(|ms| ms.iter().filter_map(|m| m.as_str()).all(|m| !Path::new(m).is_absolute()))
.unwrap_or(true)
} Try / catch
if let Err(err) = CargoWorkspaceProvider.discover_with_context(root, &ctx) {
if err.to_string().contains("must be relative") {
return Err(fix_hint(err, "edit [workspace] members in Cargo.toml to use root-relative globs"));
}
return Err(err);
} Prevention
- Always write [workspace] members as root-relative globs ("crates/*")
- Run cargo metadata --no-deps after manifest edits — cargo rejects absolute members too
- Lint manifests in CI (taplo/cargo-validate) to catch machine-generated absolute paths
When it happens
Trigger: A root Cargo.toml containing members = ["/Users/me/monorepo/crates/*"] or "D:\\repo\\crates\\*"; manifests edited by tools that write resolved absolute paths; Windows paths with a drive prefix (also absolute via the leading-root check).
Common situations: Generated Cargo.toml from a scaffolder; a teammate pasting a filesystem path into members; repos where cargo itself also rejects the absolute member (mise fails earlier with its own message).
Related errors
- workspace project {id:?} has absolute root {root:?}; roots m
- workspace project {id:?} has root {root:?} that escapes the
- workspace path {path:?} is absolute; paths must be workspace
- workspace path {path:?} escapes the workspace root
- mise upgrade --monorepo is not implemented yet
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/59b15a7461a54cc2.
Report an issue: GitHub.