{"record":{"id":"ae3d913892ac3d73","repo":"Hmbown/CodeWhale","slug":"cargo-metadata-must-contain-workspace-members-and-packages","errorCode":null,"errorMessage":"Cargo metadata must contain workspace_members and packages lists","messagePattern":"Cargo metadata must contain workspace_members and packages lists","errorType":"validation","errorClass":"ValidationError","httpStatus":null,"severity":"error","filePath":"scripts/release/validate-crate-publish-order.py","lineNumber":66,"sourceCode":"            raise ValidationError(\n                f\"cargo metadata failed with exit code {process.returncode}{suffix}\"\n            )\n        raw = process.stdout\n\n    try:\n        metadata = json.loads(raw)\n    except json.JSONDecodeError as error:\n        raise ValidationError(f\"Cargo metadata is not valid JSON: {error}\") from error\n    if not isinstance(metadata, dict):\n        raise ValidationError(\"Cargo metadata root must be an object\")\n    return metadata\n\n\ndef workspace_packages(metadata: dict[str, Any]) -> list[dict[str, Any]]:\n    members = metadata.get(\"workspace_members\")\n    packages = metadata.get(\"packages\")\n    if not isinstance(members, list) or not isinstance(packages, list):\n        raise ValidationError(\"Cargo metadata must contain workspace_members and packages lists\")\n\n    packages_by_id = {\n        package.get(\"id\"): package\n        for package in packages\n        if isinstance(package, dict) and isinstance(package.get(\"id\"), str)\n    }\n    missing_ids = [member for member in members if member not in packages_by_id]\n    if missing_ids:\n        raise ValidationError(\n            \"Cargo metadata omits workspace package ids: \" + \", \".join(missing_ids)\n        )\n    return [packages_by_id[member] for member in members]\n\n\ndef validate_order(\n    packages: list[dict[str, Any]], ordered_crates: list[str]\n) -> tuple[str, dict[str, bool]]:\n    duplicate_crates = sorted(","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/scripts/release/validate-crate-publish-order.py#L48-L84","documentation":"workspace_packages requires the metadata dict to contain both 'workspace_members' and 'packages' as lists and raises this ValidationError if either is missing or of the wrong type. These two fields are the minimum shape needed to map member ids to package manifests.","triggerScenarios":"Metadata produced by an incompatible cargo version lacking these fields; a hand-built or mocked metadata dict omitting them; a types field typo like 'workspace_member' or nested metadata under a different key.","commonSituations":"Using a very old/new cargo whose metadata schema differs; feeding the validator a custom JSON fixture for tests that doesn't mirror real cargo metadata; hand-trimming the metadata file and dropping required keys.","solutions":["Regenerate metadata with the project's pinned cargo toolchain: cargo metadata --locked --format-version 1 --no-deps","Ensure the JSON includes both workspace_members and packages as arrays","Fix the key names/types if constructing metadata manually for tests","Check rustup/cargo version matches what CI uses"],"exampleFix":"// before (fixture missing key)\n{\"packages\": [...]}\n// after\n{\"packages\": [...], \"workspace_members\": [\"id-1\"]}","handlingStrategy":"validation","validationCode":"import json\nm = json.load(open(\"cargo-metadata.json\"))\nmissing = [k for k in (\"workspace_members\", \"packages\") if not isinstance(m.get(k), list)]\nif missing:\n    raise SystemExit(f\"metadata missing list fields: {missing}\")","typeGuard":"def has_workspace_shape(m) -> bool:\n    return isinstance(m, dict) and isinstance(m.get(\"workspace_members\"), list) and isinstance(m.get(\"packages\"), list)","tryCatchPattern":"try:\n    validate_publish_order(metadata_file)\nexcept ValidationError as e:\n    if \"workspace_members and packages\" in str(e):\n        print(\"metadata shape wrong; regenerate with the pinned cargo version\")","preventionTips":["Pin the cargo toolchain used to generate metadata","Test fixtures must mirror real cargo metadata including both list fields","Re-generate rather than hand-trim metadata files"],"tags":["python","json","validation","cargo"],"backgroundTag":"schema-validation-failed","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}