Hmbown/CodeWhale · error · ValidationError

Cargo metadata omits workspace package ids

Error message

Cargo metadata omits workspace package ids: {missing_ids}

What it means

workspace_packages maps each workspace_members id to a package in 'packages' by its 'id' field and raises this ValidationError listing any member ids with no matching package entry. Every workspace member must resolve to a package for publish-order validation to work.

Solutions

  1. Regenerate metadata with a single consistent cargo version so ids match between workspace_members and packages
  2. Compare the reported missing ids against packages[].id values to spot format divergence
  3. Remove or fix the stale workspace member entries if members were hand-listed
  4. Ensure the workspace members all have valid Cargo.toml manifests so cargo includes them in packages

Example fix

// before (hand-built ids)
"workspace_members": ["codewhale-tui"]
// after (canonical cargo ids)
"workspace_members": ["path+file:///tmp/repo#codewhale-tui@0.1.0"]  // or just regenerate via cargo metadata
Defensive patterns

Strategy: validation

Validate before calling

import json
m = json.load(open("cargo-metadata.json"))
ids = {p.get("id") for p in m.get("packages", []) if isinstance(p, dict)}
missing = [i for i in m.get("workspace_members", []) if i not in ids]
if missing:
    raise SystemExit(f"members without package entries: {missing}; regenerate metadata with the same cargo version")

Try / catch

try:
    validate_publish_order(metadata_file)
except ValidationError as e:
    if "omits workspace package ids" in str(e):
        print(f"id mismatch: {e}; regenerate metadata with one consistent cargo version")

Prevention

When it happens

Trigger: A workspace member is a path dependency excluded from packages (e.g. a member whose manifest cargo skipped), ids in workspace_members that don't appear verbatim in packages[].id (cargo version formatting differences), or metadata assembled by hand with inconsistent ids.

Common situations: Mixed cargo versions generating metadata with different id formats; a new workspace member added that isn't picked up because metadata is stale; manually synthesized metadata where ids were abbreviated instead of using the canonical 'path+hash#name' form.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/872731596b81baec. Report an issue: GitHub.

Appendix: source

Thrown at scripts/release/validate-crate-publish-order.py:75

    if not isinstance(metadata, dict):
        raise ValidationError("Cargo metadata root must be an object")
    return metadata


def workspace_packages(metadata: dict[str, Any]) -> list[dict[str, Any]]:
    members = metadata.get("workspace_members")
    packages = metadata.get("packages")
    if not isinstance(members, list) or not isinstance(packages, list):
        raise ValidationError("Cargo metadata must contain workspace_members and packages lists")

    packages_by_id = {
        package.get("id"): package
        for package in packages
        if isinstance(package, dict) and isinstance(package.get("id"), str)
    }
    missing_ids = [member for member in members if member not in packages_by_id]
    if missing_ids:
        raise ValidationError(
            "Cargo metadata omits workspace package ids: " + ", ".join(missing_ids)
        )
    return [packages_by_id[member] for member in members]


def validate_order(
    packages: list[dict[str, Any]], ordered_crates: list[str]
) -> tuple[str, dict[str, bool]]:
    duplicate_crates = sorted(
        {name for name in ordered_crates if ordered_crates.count(name) > 1}
    )
    if duplicate_crates:
        raise ValidationError(
            "publish package list contains duplicates: " + ", ".join(duplicate_crates)
        )

    names = [package.get("name") for package in packages]
    if any(not isinstance(name, str) or not name for name in names):

View on GitHub (pinned to 433685b202)