Hmbown/CodeWhale · error · PersistenceBacklogError

receipt document_kind must be

Error message

receipt document_kind must be {RECEIPT_KIND}

What it means

`validate_receipt` requires that `document_kind` equal the exact string `codewhale.persistence_backlog_receipt`. This discriminator marks the JSON document as a persistence backlog measurement receipt and prevents a budget file or other document from being validated as a receipt. A wrong kind means the file is not the artifact this validator accepts.

Solutions

  1. Set `document_kind` to exactly `"codewhale.persistence_backlog_receipt"` in the receipt JSON
  2. Verify you did not pass the budget file via `--receipt` (the budget uses kind `codewhale.persistence_backlog_budget`)
  3. Regenerate the receipt with the measurement script so the kind is set correctly

Example fix

// before
{"document_kind": "codewhale.persistence_backlog_budget", ...}
// after
{"document_kind": "codewhale.persistence_backlog_receipt", ...}
Defensive patterns

Strategy: validation

Validate before calling

assert receipt.get("document_kind") == "codewhale.persistence_backlog_receipt", receipt.get("document_kind")

Type guard

def is_receipt(doc):
    return isinstance(doc, dict) and doc.get("document_kind") == "codewhale.persistence_backlog_receipt"

Try / catch

try:
    validate_receipt(receipt)
except PersistenceBacklogError as e:
    if "document_kind" in str(e):
        check_arguments_for_swapped_receipt_and_budget()

Prevention

When it happens

Trigger: Pointing `--receipt` at the budget JSON (`codewhale.persistence_backlog_budget`) or at the baseline receipt reference with an edited document_kind; a typo or rename of document_kind in a hand-written receipt.

Common situations: Swapping the --receipt and --budget argument values by mistake; renaming document_kind to a project-local value; generating a receipt with an out-of-tree tool that uses a different kind string.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at scripts/check-persistence-backlog-budget.py:148

        "cargo_version": run(["cargo", "--version"]),
        "build_profile": "test",
        "sample_count": 1,
    }


def validate_receipt(
    receipt: dict[str, Any],
    *,
    expected_source: dict[str, Any] | None = None,
    require_clean_source: bool = False,
) -> None:
    missing = [field for field in REQUIRED_RECEIPT_FIELDS if field not in receipt]
    if missing:
        raise PersistenceBacklogError(
            "receipt missing required field(s): " + ", ".join(missing)
        )
    if receipt["document_kind"] != RECEIPT_KIND:
        raise PersistenceBacklogError(f"receipt document_kind must be {RECEIPT_KIND}")
    if receipt["schema_version"] != SCHEMA_VERSION:
        raise PersistenceBacklogError("receipt schema_version changed")
    for field, expected in FIXTURE.items():
        validate_frozen_field(field, receipt[field], expected)
    if not isinstance(receipt["source_sha"], str) or not SOURCE_SHA_PATTERN.fullmatch(
        receipt["source_sha"]
    ):
        raise PersistenceBacklogError("receipt source_sha must be an exact lowercase Git SHA")
    if type(receipt["source_dirty"]) is not bool:
        raise PersistenceBacklogError("receipt source_dirty must be boolean")
    for field, prefix in (("rustc_version", "rustc "), ("cargo_version", "cargo ")):
        if not isinstance(receipt[field], str) or not receipt[field].startswith(prefix):
            raise PersistenceBacklogError(f"receipt {field} must be a version string")
    validate_frozen_field("build_profile", receipt["build_profile"], "test")
    validate_frozen_field("sample_count", receipt["sample_count"], 1)
    if expected_source is not None:
        for field in (
            "source_sha",

View on GitHub (pinned to 433685b202)