Hmbown/CodeWhale · error · RuntimeContractError

document_kind must be ` `, got

Error message

{source} document_kind must be `{expected_kind}`, got {actual_kind!r}

What it means

validate_document checks that a parsed receipt/budget JSON has the required `document_kind` discriminator equal to the expected kind (codewhale.runtime_contract_receipt or codewhale.runtime_contract_budget). A mismatch or missing key raises this RuntimeContractError, preventing a receipt from being validated as a budget or vice versa.

Solutions

  1. Check the `got` value in the message: pass the receipt file to --receipt and keep scripts/runtime-contract-budget.json as the budget input.
  2. Set document_kind to the expected string ("codewhale.runtime_contract_receipt" or "codewhale.runtime_contract_budget") if the file's kind was renamed.
  3. Regenerate the document with the current tool version if it predates the schema rename.

Example fix

// before (receipt.json)
{"document_kind": "codewhale.runtime_contract_budget", ...}
// after
{"document_kind": "codewhale.runtime_contract_receipt", ...}
Defensive patterns

Strategy: validation

Validate before calling

import json
from pathlib import Path
doc = json.loads(Path(path).read_text(encoding="utf-8"))
expected = "codewhale.runtime_contract_receipt"
if doc.get("document_kind") != expected:
    raise SystemExit(f"{path}: document_kind must be {expected!r}")

Type guard

def has_document_kind(doc, kind: str) -> bool:
    return isinstance(doc, dict) and doc.get("document_kind") == kind

Try / catch

try:
    validate_document(doc, RECEIPT_KIND, "receipt")
except RuntimeContractError as e:
    print(e); sys.exit(1)  # message shows expected vs actual kind

Prevention

When it happens

Trigger: Passing a budget JSON via --receipt (or the receipt path to the budget loader); a document missing document_kind entirely; an old or differently-named discriminator field.

Common situations: Swapping the two file arguments; pointing the checker at an unrelated JSON config; a schema rename between tool versions left an old file with a stale document_kind.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at scripts/check-runtime-contract-budget.py:177

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 433685b202)