Hmbown/CodeWhale · error · PersistenceBacklogError

must be a JSON object

Error message

{label} must be a JSON object

What it means

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.

Solutions

  1. Inspect the file's top level and wrap the content in the expected object shape
  2. Regenerate the receipt/budget with the current producing tool so it emits a JSON object
  3. Update the writer to serialize an object with the fields the checker expects
  4. If the checker must accept a new shape, extend load_json rather than editing data ad hoc

Example fix

// before
[1, 2, 3]
// after
{"entries": [1, 2, 3]}
Defensive patterns

Strategy: type-guard

Validate before calling

import json
doc = json.loads(Path("receipt.json").read_text())
assert isinstance(doc, dict), "receipt must be a JSON object at top level"

Type guard

def is_json_object(value: object) -> bool:
    return isinstance(value, dict)

if not is_json_object(doc):
    raise PersistenceBacklogError("receipt must be a JSON object")

Try / catch

try:
    doc = load_json(path, "receipt")
except PersistenceBacklogError as exc:
    print(f"bad receipt shape: {exc}"); sys.exit(1)

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/e5b2661c8b11c818. Report an issue: GitHub.

Appendix: 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 433685b202)