Hmbown/CodeWhale · error · PersistenceBacklogError
{label} must be a JSON object
Error message
{label} must be a JSON object What it means
After successfully parsing the budget or receipt JSON text, load_json requires the top-level value to be a JSON object (dict), not an array, string, number, or null. This error names which label ('budget'/'baseline receipt') failed the shape check before any field validation runs.
Source
Thrown at scripts/check-persistence-backlog-budget.py:92
"rss_after_delta_bytes",
)
RSS_SAMPLE_FIELDS = ("rss_before_bytes", "rss_during_bytes", "rss_after_bytes")
RSS_DELTA_FIELDS = ("rss_during_delta_bytes", "rss_after_delta_bytes")
SUPPORTED_PLATFORMS = {"linux", "macos", "windows"}
SOURCE_SHA_PATTERN = re.compile(r"[0-9a-f]{40}")
class PersistenceBacklogError(ValueError):
"""A receipt or budget broke the measurement contract."""
def load_json(path: Path, label: str) -> dict[str, Any]:
try:
value = json.loads(path.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError) as error:
raise PersistenceBacklogError(f"invalid {label} {path}: {error}") from error
if not isinstance(value, dict):
raise PersistenceBacklogError(f"{label} must be a JSON object")
return value
def non_negative_integer(value: Any, field: str) -> int:
if isinstance(value, bool) or not isinstance(value, int) or value < 0:
raise PersistenceBacklogError(f"{field} must be a non-negative integer")
return value
def validate_frozen_field(field: str, value: Any, expected: Any) -> None:
if type(value) is not type(expected) or value != expected:
raise PersistenceBacklogError(
f"receipt {field} must remain {expected!r}, got {value!r}"
)
def current_source_identity() -> dict[str, Any]:
def run(command: list[str]) -> str:View on GitHub (pinned to 8880682c63)
Solutions
- Open the named file and wrap the top-level value in an object: {"entries": [...]} or the documented field names.
- Compare against the checked-in format used by the existing budget/receipt files in scripts/.
- If the array shape is the intended new format, update load_json and the downstream validators in the same change with tests.
- Re-run scripts/check-persistence-backlog-budget.py to confirm field-level validation proceeds.
Example fix
# before: scripts/persistence-backlog-budget.json
[{"max_files": 5000, "max_bytes": 1048576}]
# after
{"max_files": 5000, "max_bytes": 1048576} Defensive patterns
Strategy: type-guard
Validate before calling
import json
def top_level_is_object(path) -> bool:
return isinstance(json.loads(path.read_text(encoding="utf-8")), dict) Type guard
def is_json_object(value: object) -> bool:
return isinstance(value, dict) Prevention
- Keep the budget/receipt top-level shape an object; nest arrays under named keys.
- Copy the checked-in file's structure when adding entries instead of inventing a new shape.
- Add a schema smoke-test in CI that asserts isinstance(loaded, dict) before the full check runs.
When it happens
Trigger: The budget file contains a JSON array of entries (e.g. '[{"max_files": ...}]'), a bare string/number, or 'null', all of which parse fine but are not objects. Only a {"...": ...} document at the top level is accepted.
Common situations: Hand-writing the budget as a list of rules; tools that emit NDJSON or a top-level array; an empty file left as 'null' by a serializer; refactoring the file format without updating the checker's expectation.
Related errors
- invalid {label} {path}: {error}
- {field} must be a non-negative integer
- baseline provenance build profile/sample count changed
- {kind} field `{dotted_names}` must be sorted unique non-empt
- ${label} does not match the authoritative inventory; missing
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/e5b2661c8b11c818.
Report an issue: GitHub.