Hmbown/CodeWhale · error · RuntimeContractError
invalid : top level must be an object
Error message
invalid {kind} {path}: top level must be an object What it means
After successfully parsing the JSON, load_json requires the top-level value to be a JSON object (dict). Arrays, strings, numbers, or null at the top level raise this RuntimeContractError, because receipt and budget documents are always objects with document_kind/schema_version fields.
Solutions
- Open the file and confirm the top level is `{...}`; wrap the value in an object if the producer wrote an array or scalar.
- Fix the producer so it emits a single receipt/budget object with document_kind and schema_version fields.
- Point --receipt at the correct per-run receipt file rather than an aggregate list.
Example fix
// before (receipt.json)
[{"document_kind": "codewhale.runtime_contract_receipt"}]
// after
{"document_kind": "codewhale.runtime_contract_receipt", "schema_version": 1} Defensive patterns
Strategy: type-guard
Validate before calling
import json
from pathlib import Path
doc = json.loads(Path(path).read_text(encoding="utf-8"))
if not isinstance(doc, dict):
raise SystemExit(f"{path}: top level must be a JSON object") Type guard
def is_receipt_object(path) -> bool:
import json
from pathlib import Path
try:
return isinstance(json.loads(Path(path).read_text(encoding="utf-8")), dict)
except Exception:
return False Try / catch
try:
doc = load_json(path, "receipt")
except RuntimeContractError as e:
if "top level must be an object" in str(e):
print(f"{path} holds a non-object JSON value; fix the producer")
raise Prevention
- Producers must serialize a single receipt/budget object, never a bare list or scalar.
- Sanity-check generated files by asserting `isinstance(doc, dict)` right after writing.
- Keep placeholder/fixture JSON files shaped like real documents.
When it happens
Trigger: Passing a --receipt file whose content is a JSON array, string, number, boolean, or null — e.g. a file holding `[1,2,3]`, a list of receipts, or `null` from a failed serialization.
Common situations: A tool wrote a JSON array of results instead of a single object; a placeholder or test fixture file was pointed at; a script serialized the wrong variable.
Related errors
- document_kind must be ` `, got
- Cargo metadata must contain workspace_members and packages…
- Cargo metadata root must be an object
- must be a JSON object
- measurement receipt must be an object
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/c2609820ae61b57a.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/check-runtime-contract-budget.py:168
)
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 433685b202)