{"record":{"id":"e5b2661c8b11c818","repo":"Hmbown/CodeWhale","slug":"label-must-be-a-json-object","errorCode":null,"errorMessage":"{label} must be a JSON object","messagePattern":"(.+?) must be a JSON object","errorType":"validation","errorClass":"PersistenceBacklogError","httpStatus":null,"severity":"error","filePath":"scripts/check-persistence-backlog-budget.py","lineNumber":92,"sourceCode":"    \"rss_after_delta_bytes\",\n)\nRSS_SAMPLE_FIELDS = (\"rss_before_bytes\", \"rss_during_bytes\", \"rss_after_bytes\")\nRSS_DELTA_FIELDS = (\"rss_during_delta_bytes\", \"rss_after_delta_bytes\")\nSUPPORTED_PLATFORMS = {\"linux\", \"macos\", \"windows\"}\nSOURCE_SHA_PATTERN = re.compile(r\"[0-9a-f]{40}\")\n\n\nclass PersistenceBacklogError(ValueError):\n    \"\"\"A receipt or budget broke the measurement contract.\"\"\"\n\n\ndef load_json(path: Path, label: str) -> dict[str, Any]:\n    try:\n        value = json.loads(path.read_text(encoding=\"utf-8\"))\n    except (OSError, json.JSONDecodeError) as error:\n        raise PersistenceBacklogError(f\"invalid {label} {path}: {error}\") from error\n    if not isinstance(value, dict):\n        raise PersistenceBacklogError(f\"{label} must be a JSON object\")\n    return value\n\n\ndef non_negative_integer(value: Any, field: str) -> int:\n    if isinstance(value, bool) or not isinstance(value, int) or value < 0:\n        raise PersistenceBacklogError(f\"{field} must be a non-negative integer\")\n    return value\n\n\ndef validate_frozen_field(field: str, value: Any, expected: Any) -> None:\n    if type(value) is not type(expected) or value != expected:\n        raise PersistenceBacklogError(\n            f\"receipt {field} must remain {expected!r}, got {value!r}\"\n        )\n\n\ndef current_source_identity() -> dict[str, Any]:\n    def run(command: list[str]) -> str:","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/scripts/check-persistence-backlog-budget.py#L74-L110","documentation":"After successfully parsing a labeled file, load_json additionally requires the top-level value to be a JSON object (dict). Arrays, strings, numbers, or null at the top level raise PersistenceBacklogError, because the persistence-backlog budget checker needs named fields from the receipt and budget documents.","triggerScenarios":"A receipt or budget file whose root is a JSON array or scalar — e.g. the producer exported a list of entries instead of an object keyed by field name, or the file was hand-edited/replaced with a differently shaped document.","commonSituations":"Schema drift between the tool that writes the receipt and this checker; someone flattening the JSON during a manual edit; a pipeline step emitting an array of per-day records where the checker expects one object.","solutions":["Inspect the file's top level and wrap the content in the expected object shape","Regenerate the receipt/budget with the current producing tool so it emits a JSON object","Update the writer to serialize an object with the fields the checker expects","If the checker must accept a new shape, extend load_json rather than editing data ad hoc"],"exampleFix":"// before\n[1, 2, 3]\n// after\n{\"entries\": [1, 2, 3]}","handlingStrategy":"type-guard","validationCode":"import json\ndoc = json.loads(Path(\"receipt.json\").read_text())\nassert isinstance(doc, dict), \"receipt must be a JSON object at top level\"","typeGuard":"def is_json_object(value: object) -> bool:\n    return isinstance(value, dict)\n\nif not is_json_object(doc):\n    raise PersistenceBacklogError(\"receipt must be a JSON object\")","tryCatchPattern":"try:\n    doc = load_json(path, \"receipt\")\nexcept PersistenceBacklogError as exc:\n    print(f\"bad receipt shape: {exc}\"); sys.exit(1)","preventionTips":["Keep the writer and checker schemas in sync; change both in the same PR","Never replace the object root with an array when flattening manually","Snapshot a known-good receipt and diff against it after pipeline changes","Add a smoke test that loads the current receipt through load_json"],"tags":["json","validation","schema"],"backgroundTag":"schema-validation-failed","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"}