Hmbown/CodeWhale · error · RuntimeContractError

invalid {kind} {path}: top level must be an object

Error message

invalid {kind} {path}: top level must be an object

What it means

The JSON file parsed successfully but its top level is not an object — the checker requires a dict to hold document_kind, schema_version, and the metric tree. A top-level array, string, or number fails immediately before any field validation runs. This guards the document shape at the earliest possible point.

Source

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

        )
        for stage, label in REPRESENTATIVE_STAGES
    ),
)


class RuntimeContractError(ValueError):
    """A receipt or budget is missing a required, well-typed metric."""


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(

View on GitHub (pinned to 8880682c63)

Solutions

  1. Open the file and confirm it starts with `{`; if it is an array, extract the single relevant object
  2. Regenerate the file with scripts/measure-runtime-contract.py rather than hand-assembling it
  3. Pass one file per document to --receipt

Example fix

// before — file contains a top-level array
[ { "document_kind": "codewhale.runtime_contract_receipt", ... } ]
// after
{ "document_kind": "codewhale.runtime_contract_receipt", ... }
Defensive patterns

Strategy: type-guard

Validate before calling

doc = json.loads(text)
assert isinstance(doc, dict), f'top level must be an object, got {type(doc).__name__}'

Type guard

def is_contract_document(value):
    return isinstance(value, dict) and isinstance(value.get('document_kind'), str)

Prevention

When it happens

Trigger: Wrapping receipts in a JSON array (for example multi-platform bundles); storing a bare string; saving a JSON fragment instead of the full document.

Common situations: Collecting receipts from several CI lanes into one file; tooling that emits arrays by default.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/c2609820ae61b57a. Report an issue: GitHub.