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

  1. Change the member entry to a root-relative pattern such as "crates/*"
  2. If the crate lives outside the workspace root, move it inside or relocate the workspace root — absolute members are not supported
  3. 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

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


AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17). Data as JSON: /api/errors/59b15a7461a54cc2. Report an issue: GitHub.