{"record":{"id":"b9d9a383d97a5fcf","repo":"Hmbown/CodeWhale","slug":"workspace-packages-have-mixed-versions-rendered","errorCode":null,"errorMessage":"workspace packages have mixed versions: {rendered}","messagePattern":"workspace packages have mixed versions: (.+?)","errorType":"validation","errorClass":"ValidationError","httpStatus":null,"severity":"error","filePath":"scripts/release/validate-crate-publish-order.py","lineNumber":101,"sourceCode":") -> tuple[str, dict[str, bool]]:\n    duplicate_crates = sorted(\n        {name for name in ordered_crates if ordered_crates.count(name) > 1}\n    )\n    if duplicate_crates:\n        raise ValidationError(\n            \"publish package list contains duplicates: \" + \", \".join(duplicate_crates)\n        )\n\n    names = [package.get(\"name\") for package in packages]\n    if any(not isinstance(name, str) or not name for name in names):\n        raise ValidationError(\"workspace package is missing a name\")\n    if len(set(names)) != len(names):\n        raise ValidationError(\"Cargo metadata contains duplicate workspace package names\")\n\n    versions = sorted({package.get(\"version\") for package in packages})\n    if len(versions) != 1 or not isinstance(versions[0], str) or not versions[0]:\n        rendered = \", \".join(str(version) for version in versions)\n        raise ValidationError(f\"workspace packages have mixed versions: {rendered}\")\n\n    workspace_by_name = {package[\"name\"]: package for package in packages}\n    release_names = sorted(\n        name for name in workspace_by_name if name.startswith(\"codewhale-\")\n    )\n    ordered_set = set(ordered_crates)\n    missing = sorted(set(release_names) - ordered_set)\n    extra = sorted(ordered_set - set(release_names))\n    if missing or extra:\n        messages = []\n        if missing:\n            messages.append(\"publish package list is missing workspace crates: \" + \" \".join(missing))\n        if extra:\n            messages.append(\n                \"publish package list contains non-workspace crates: \" + \" \".join(extra)\n            )\n        raise ValidationError(\"\\n\".join(messages))\n","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/scripts/release/validate-crate-publish-order.py#L83-L119","documentation":"The set of workspace package versions does not reduce to exactly one non-empty string -- the crates are not all on the same version. The release process publishes every codewhale-* crate in lockstep and the validator returns the single discovered version to the publish script, so mixed versions (or a missing/non-string version) abort validation with the versions rendered in the message.","triggerScenarios":"One crate's Cargo.toml carries a hardcoded version while the rest use the workspace version; a release bump script updated most crates but missed one; a newly added crate was created with a different initial version.","commonSituations":"Release preparation where the version-anchoring convention (workspace-inherited version) is not followed by every member.","solutions":["Set the straggler crate to inherit the workspace version: in its Cargo.toml use version.workspace = true under [package]","Ensure [workspace.package] declares the shared version","Re-run the validator; cargo metadata --locked --format-version 1 --no-deps | jq -r '.packages[].version' | sort -u should print exactly one version"],"exampleFix":"# crates/<straggler>/Cargo.toml: before\n[package]\nname = \"codewhale-x\"\nversion = \"0.4.0\"\n\n# after\n[package]\nname = \"codewhale-x\"\nversion.workspace = true","handlingStrategy":"validation","validationCode":"# Pre-release check: exactly one version across the workspace\nimport json, subprocess\n\nmeta = json.loads(subprocess.run(\n    [\"cargo\", \"metadata\", \"--locked\", \"--format-version\", \"1\", \"--no-deps\"],\n    capture_output=True, text=True, check=True).stdout)\nversions = {p[\"version\"] for p in meta[\"packages\"] if p[\"id\"] in set(meta[\"workspace_members\"])}\nassert len(versions) == 1, f\"align versions before release: {sorted(versions)}\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use version.workspace = true in every member so the workspace version is the single knob","Run the version check as part of the release checklist before tagging"],"tags":["release","versioning","cargo","workspace","python"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}