Hmbown/CodeWhale · error · RuntimeContractError
{source} document_kind must be `{expected_kind}`, got {actua
Error message
{source} document_kind must be `{expected_kind}`, got {actual_kind!r} What it means
validate_document compared the document_kind discriminator and it does not match the expected receipt or budget kind string (`codewhale.runtime_contract_receipt` vs `codewhale.runtime_contract_budget`). The discriminator prevents passing the wrong file into the wrong slot and rejects receipts produced by other gates (for example the persistence-backlog script). A missing document_kind surfaces as None in the message.
Source
Thrown at scripts/check-runtime-contract-budget.py:176
def load_json(path: Path, kind: str) -> dict[str, Any]:
try:
document = json.loads(path.read_text(encoding="utf-8"))
except FileNotFoundError as error:
raise RuntimeContractError(f"missing {kind}: {path}") from error
except (OSError, json.JSONDecodeError) as error:
raise RuntimeContractError(f"invalid {kind} {path}: {error}") from error
if not isinstance(document, dict):
raise RuntimeContractError(f"invalid {kind} {path}: top level must be an object")
return document
def validate_document(
document: dict[str, Any], expected_kind: str, source: str
) -> None:
actual_kind = document.get("document_kind")
if actual_kind != expected_kind:
raise RuntimeContractError(
f"{source} document_kind must be `{expected_kind}`, got {actual_kind!r}"
)
version = document.get("schema_version")
if (
isinstance(version, bool)
or not isinstance(version, int)
or version != SCHEMA_VERSION
):
raise RuntimeContractError(
f"{source} schema_version must be {SCHEMA_VERSION}, got {version!r}"
)
def required_value(document: dict[str, Any], path: MetricPath, kind: str) -> Any:
value: Any = document
dotted = ".".join(path)
for part in path:
if not isinstance(value, dict) or part not in value:View on GitHub (pinned to 8880682c63)
Solutions
- Confirm which file went where: --receipt wants document_kind `codewhale.runtime_contract_receipt`, the budget wants `codewhale.runtime_contract_budget`
- Regenerate receipts with scripts/measure-runtime-contract.py so the discriminator is written for you
- Add the correct document_kind key when hand-building test fixtures
Example fix
# before python3 scripts/check-runtime-contract-budget.py --receipt scripts/runtime-contract-budget.json # after python3 scripts/check-runtime-contract-budget.py --receipt scripts/runtime-contract-receipt.json
Defensive patterns
Strategy: validation
Validate before calling
expected = 'codewhale.runtime_contract_receipt' if is_receipt else 'codewhale.runtime_contract_budget'
assert doc.get('document_kind') == expected, doc.get('document_kind') Type guard
def is_receipt(doc):
return isinstance(doc, dict) and doc.get('document_kind') == 'codewhale.runtime_contract_receipt' Prevention
- Double-check which slot (--receipt vs --budget) each file goes into
- Use the measure script to produce receipts so the discriminator is set
- Include document_kind in hand-built fixtures
When it happens
Trigger: Passing the budget file to --receipt; passing a persistence-backlog receipt; hand-building a receipt without the document_kind key; swapping the --receipt and --budget arguments.
Common situations: Copy-pasted CI commands; repositories hosting several receipt formats side by side.
Related errors
- {kind} is missing required field `{dotted}`
- receipt missing required field(s): " + ", ".join(missing)
- baseline provenance build profile/sample count changed
- invalid {kind} {path}: {error}
- invalid {kind} {path}: top level must be an object
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/4f6d251104112914.
Report an issue: GitHub.