{"record":{"id":"d2c3686debd9358b","repo":"Hmbown/CodeWhale","slug":"measurement-receipt-must-be-an-object","errorCode":null,"errorMessage":"measurement receipt must be an object","messagePattern":"measurement receipt must be an object","errorType":"console","errorClass":"PersistenceBacklogError","httpStatus":null,"severity":"error","filePath":"scripts/check-persistence-backlog-budget.py","lineNumber":392,"sourceCode":"    env[\"CARGO_NET_OFFLINE\"] = \"true\"\n    result = subprocess.run(\n        [sys.executable, str(MEASURE_SCRIPT)],\n        cwd=ROOT,\n        env=env,\n        text=True,\n        capture_output=True,\n        check=False,\n    )\n    sys.stderr.write(result.stderr)\n    if result.returncode != 0:\n        sys.stdout.write(result.stdout)\n        raise PersistenceBacklogError(\"measurement command failed\")\n    try:\n        receipt = json.loads(result.stdout)\n    except json.JSONDecodeError as error:\n        raise PersistenceBacklogError(f\"measurement emitted invalid JSON: {error}\") from error\n    if not isinstance(receipt, dict):\n        raise PersistenceBacklogError(\"measurement receipt must be an object\")\n    return receipt\n\n\ndef main() -> int:\n    parser = argparse.ArgumentParser(description=__doc__)\n    parser.add_argument(\"--receipt\", type=Path, help=\"check an existing receipt\")\n    parser.add_argument(\"--budget\", type=Path, default=BUDGET_PATH)\n    args = parser.parse_args()\n    try:\n        expected_source = current_source_identity()\n        receipt = load_json(args.receipt, \"receipt\") if args.receipt else measure()\n        budget = load_json(args.budget, \"budget\")\n        baseline_receipt = load_json(BASELINE_RECEIPT_PATH, \"baseline receipt\")\n        validate_baseline_receipt(budget, baseline_receipt)\n        increases, decreases = compare(\n            receipt,\n            budget,\n            expected_source=expected_source,","sourceCodeStart":374,"sourceCodeEnd":410,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/scripts/check-persistence-backlog-budget.py#L374-L410","documentation":"After successful JSON parsing, measure() requires the decoded receipt to be a dict/object. This error means the measurement command emitted valid JSON that is not an object (e.g. a list, string, or number), so it cannot be used as a receipt. It protects downstream field access into the receipt.","triggerScenarios":"Running the budget check when the measurement command's stdout parses to a JSON value whose type is not dict — e.g. the tool prints a JSON array of samples or a bare string instead of a receipt object.","commonSituations":"Measurement tool version drift changing the output shape; a wrapper script printing a summary array; accidentally invoking a different command that emits non-object JSON.","solutions":["Update the measurement command to emit a top-level JSON object receipt","Check the measurement tool version matches what the guard expects","Inspect stdout of the command directly to confirm the emitted shape"],"exampleFix":"// before: print(json.dumps([r1, r2]))\n// after:  print(json.dumps({\"accepted_requests\": ..., \"applied_version\": ..., ...}))","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"def is_receipt(value: object) -> bool:\n    return isinstance(value, dict) and all(k in value for k in ('accepted_requests', 'applied_version'))","tryCatchPattern":"receipt = json.loads(result.stdout)\nif not isinstance(receipt, dict):\n    raise PersistenceBacklogError(f\"expected object receipt, got {type(receipt).__name__}\")","preventionTips":["Emit a top-level JSON object from the measurement tool","Add a schema check on the receipt right after parsing","Keep the receipt shape stable across tool versions"],"tags":["python","json","schema","type-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"}