{"record":{"id":"74abeca03f99212a","repo":"Hmbown/CodeWhale","slug":"measurement-top-level-must-be-an-object","errorCode":null,"errorMessage":"measurement top level must be an object","messagePattern":"measurement top level must be an object","errorType":"exception","errorClass":"RuntimeContractError","httpStatus":null,"severity":"error","filePath":"scripts/check-runtime-contract-budget.py","lineNumber":420,"sourceCode":"        [sys.executable, str(MEASURE_SCRIPT)],\n        cwd=REPO_ROOT,\n        env=env,\n        capture_output=True,\n        text=True,\n        check=False,\n    )\n    sys.stderr.write(proc.stderr)\n    if proc.returncode != 0:\n        sys.stdout.write(proc.stdout)\n        raise RuntimeContractError(\n            f\"runtime-contract measurement failed with exit code {proc.returncode}\"\n        )\n    try:\n        receipt = json.loads(proc.stdout)\n    except json.JSONDecodeError as error:\n        raise RuntimeContractError(f\"measurement emitted invalid JSON: {error}\") from error\n    if not isinstance(receipt, dict):\n        raise RuntimeContractError(\"measurement top level must be an object\")\n    validate_receipt(receipt)\n    return receipt\n\n\ndef update_command(receipt_path: Path | None, budget_path: Path) -> str:\n    parts = [\"python3\", \"scripts/check-runtime-contract-budget.py\"]\n    if receipt_path is not None:\n        parts.extend([\"--receipt\", str(receipt_path)])\n    if budget_path != BUDGET_PATH:\n        parts.extend([\"--budget\", str(budget_path)])\n    parts.append(\"--update\")\n    return shlex.join(parts)\n\n\nFRAGMENT_MODULE = REPO_ROOT / \"crates\" / \"core\" / \"src\" / \"fragments.rs\"\nFRAGMENT_MAX_TOKENS_CEILING = 10_000\nFRAGMENT_MAX_BYTES_CEILING = FRAGMENT_MAX_TOKENS_CEILING * 4\nFRAGMENT_DEFAULT_MAX_BYTES_CEILING = 4 * 1024","sourceCodeStart":402,"sourceCodeEnd":438,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/scripts/check-runtime-contract-budget.py#L402-L438","documentation":"run_measurement requires the parsed measurement output to be a JSON object (dict) at the top level, since the receipt schema is keyed (kind, schema_version, metrics, ...). If json.loads yields a list, string, number, or null, the checker raises RuntimeContractError before validate_receipt runs. This catches measurement scripts that emit a bare array or wrapper instead of the canonical receipt object.","triggerScenarios":"measure-runtime-contract.py (or a substitute script producing stdout) emits a JSON array, a bare value, or `null` instead of the receipt object.","commonSituations":"A rewritten or older measurement script emitting a different shape; piping in output of a different tool; accidentally substituting the MEASURE_SCRIPT or trimming wrapper code that wrapped the object.","solutions":["Ensure the measurement emits the full receipt object starting with `{` (including kind/schema_version fields).","Check the stdout in the error output — if it is `[...]`, update the emitter to wrap results in an object.","Run the stock scripts/measure-runtime-contract.py rather than a modified/local variant.","If a wrapper script must transform output, keep the top-level object intact and add fields instead."],"exampleFix":"# before\nprint(json.dumps(metrics))\n# after\nprint(json.dumps({\"kind\": \"codewhale.runtime_contract_receipt\", \"schema_version\": 1, **metrics}))","handlingStrategy":"type-guard","validationCode":"import json\nreceipt = json.loads(proc.stdout)\nassert isinstance(receipt, dict), \"measurement top level must be an object\"","typeGuard":"def is_receipt(doc: object) -> bool:\n    return isinstance(doc, dict) and doc.get(\"kind\") == \"codewhale.runtime_contract_receipt\"","tryCatchPattern":"try:\n    validate_receipt(json.loads(proc.stdout))\nexcept (json.JSONDecodeError, TypeError) as e:\n    print(f\"unexpected measurement output shape: {e}\", file=sys.stderr)","preventionTips":["Emit a dict with kind/schema_version keys, never a bare list or scalar.","Pin the measurement script path; do not substitute local variants.","Add a schema check right after json.loads in any wrapper tooling."],"tags":["json","schema","contract-check","shape-mismatch"],"backgroundTag":"unexpected-response-shape","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}