{"record":{"id":"d93040f3c9fcb84c","repo":"Hmbown/CodeWhale","slug":"receipt-field-must-be-a-version-string","errorCode":null,"errorMessage":"receipt {field} must be a version string","messagePattern":"receipt (.+?) must be a version string","errorType":"exception","errorClass":"PersistenceBacklogError","httpStatus":null,"severity":"error","filePath":"scripts/check-persistence-backlog-budget.py","lineNumber":161,"sourceCode":"    if missing:\n        raise PersistenceBacklogError(\n            \"receipt missing required field(s): \" + \", \".join(missing)\n        )\n    if receipt[\"document_kind\"] != RECEIPT_KIND:\n        raise PersistenceBacklogError(f\"receipt document_kind must be {RECEIPT_KIND}\")\n    if receipt[\"schema_version\"] != SCHEMA_VERSION:\n        raise PersistenceBacklogError(\"receipt schema_version changed\")\n    for field, expected in FIXTURE.items():\n        validate_frozen_field(field, receipt[field], expected)\n    if not isinstance(receipt[\"source_sha\"], str) or not SOURCE_SHA_PATTERN.fullmatch(\n        receipt[\"source_sha\"]\n    ):\n        raise PersistenceBacklogError(\"receipt source_sha must be an exact lowercase Git SHA\")\n    if type(receipt[\"source_dirty\"]) is not bool:\n        raise PersistenceBacklogError(\"receipt source_dirty must be boolean\")\n    for field, prefix in ((\"rustc_version\", \"rustc \"), (\"cargo_version\", \"cargo \")):\n        if not isinstance(receipt[field], str) or not receipt[field].startswith(prefix):\n            raise PersistenceBacklogError(f\"receipt {field} must be a version string\")\n    validate_frozen_field(\"build_profile\", receipt[\"build_profile\"], \"test\")\n    validate_frozen_field(\"sample_count\", receipt[\"sample_count\"], 1)\n    if expected_source is not None:\n        for field in (\n            \"source_sha\",\n            \"source_dirty\",\n            \"rustc_version\",\n            \"cargo_version\",\n            \"build_profile\",\n            \"sample_count\",\n        ):\n            if receipt[field] != expected_source[field]:\n                raise PersistenceBacklogError(\n                    f\"receipt {field} does not match the checked source\"\n                )\n    if require_clean_source and receipt[\"source_dirty\"]:\n        raise PersistenceBacklogError(\"persistence measurement source tree is dirty\")\n    platform = receipt[\"platform\"]","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/scripts/check-persistence-backlog-budget.py#L143-L179","documentation":"Raised in validate_receipt (scripts/check-persistence-backlog-budget.py:159-161) when rustc_version or cargo_version is not a string or does not start with \"rustc \" / \"cargo \". The checker stores the full first line of `rustc --version` / `cargo --version` output so receipts are pinned to the exact toolchain and can be compared verbatim against the live toolchain later.","triggerScenarios":"Storing only the bare version (\"1.75.0\") without the leading program name; empty or null values; a wrapper/proxy toolchain whose --version output starts differently; cross-compile setups where the captured output came from a different binary.","commonSituations":"Custom rustc wrappers in CI; receipts from env plumbing (CODEWHALE_TEST_PERSISTENCE_BACKLOG_RUSTC_VERSION) that stripped the prefix; hand-filled provenance.","solutions":["Regenerate the receipt so toolchain strings are captured verbatim from `rustc --version` / `cargo --version`.","Ensure the Rust test writes the env-provided string unchanged rather than reformatting it.","Run the check with the same toolchain (rustup default / +toolchain) used for measurement."],"exampleFix":"// receipt (before)\n\"rustc_version\": \"1.75.0\"\n// receipt (after)\n\"rustc_version\": \"rustc 1.75.0 (82e1608dfa6f9b55c8a34c4193a27fe0ba1620f3 2023-12-21)\"","handlingStrategy":"type-guard","validationCode":"for field, prefix in ((\"rustc_version\", \"rustc \"), (\"cargo_version\", \"cargo \")):\n    v = receipt.get(field)\n    if not isinstance(v, str) or not v.startswith(prefix):\n        sys.exit(f\"{field} malformed; store full `--version` output verbatim\")","typeGuard":"def is_version_string(value, prefix: str) -> bool:\n    return isinstance(value, str) and value.startswith(prefix)","tryCatchPattern":"try:\n    validate_receipt(receipt)\nexcept PersistenceBacklogError as e:\n    if \"must be a version string\" in str(e):\n        raise RuntimeError(\"toolchain string reformatted; recapture raw --version output\") from e\n    raise","preventionTips":["Record the complete first line of rustc --version / cargo --version, prefix included.","Pin the toolchain (rustup override) so measure and check see identical strings.","Avoid wrapper shims that alter --version output in the measurement lane."],"tags":["validation","toolchain","provenance"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}