Hmbown/CodeWhale · error · PersistenceBacklogError

budget needs ceilings and baseline_observation objects

Error message

budget needs ceilings and baseline_observation objects

What it means

validate_budget requires both budget.ceilings and budget.baseline_observation to be JSON objects (dicts). These two sections hold the one-way ceiling fields and the recorded baseline numbers the budget is built from. If either is missing, null, or a non-object type, the budget cannot be validated or compared and this error is raised.

Solutions

  1. Add/restore both "ceilings" and "baseline_observation" as JSON objects in the budget
  2. Regenerate the budget from the measurement pipeline to get a complete document
  3. Validate the JSON structure with a quick script before running the checker

Example fix

// before
{ "ceilings": [1, 2], "baseline_observation": null }
// after
{ "ceilings": { "retained_queued_requests": 1 }, "baseline_observation": { "retained_queued_requests": 1 } }
Defensive patterns

Strategy: validation

Validate before calling

budget = json.load(open("scripts/persistence-backlog-budget.json"))
assert isinstance(budget.get("ceilings"), dict) and isinstance(budget.get("baseline_observation"), dict), "budget needs ceilings and baseline_observation objects"

Type guard

def has_required_sections(doc):
    return isinstance(doc, dict) and isinstance(doc.get("ceilings"), dict) and isinstance(doc.get("baseline_observation"), dict)

Try / catch

try:
    validate_budget(budget)
except PersistenceBacklogError as e:
    if "needs ceilings and baseline_observation" in str(e):
        print("budget file is truncated or malformed; regenerate it")
    raise

Prevention

When it happens

Trigger: compare calls validate_budget and budget['ceilings'] or budget['baseline_observation'] is absent, null, a list, or some other non-dict value.

Common situations: A partially written or truncated budget file; an edit that replaced ceilings with a flat array; a schema-version-1 budget whose sections were named differently; merging JSON files and dropping one section.

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/c8de3e97ab7b440b. Report an issue: GitHub.

Appendix: source

Thrown at scripts/check-persistence-backlog-budget.py:260

def validate_budget(budget: dict[str, Any]) -> None:
    if budget.get("document_kind") != BUDGET_KIND:
        raise PersistenceBacklogError(f"budget document_kind must be {BUDGET_KIND}")
    if budget.get("schema_version") != SCHEMA_VERSION:
        raise PersistenceBacklogError("budget schema_version changed")
    fixture = budget.get("fixture")
    if not isinstance(fixture, dict) or set(fixture) != set(FIXTURE):
        raise PersistenceBacklogError("budget fixture no longer matches the frozen workload")
    for field, expected in FIXTURE.items():
        if type(fixture[field]) is not type(expected) or fixture[field] != expected:
            raise PersistenceBacklogError(
                f"budget fixture.{field} must remain {expected!r}"
            )
    if budget.get("baseline_receipt") != BASELINE_RECEIPT_REFERENCE:
        raise PersistenceBacklogError("budget baseline_receipt path changed")
    ceilings = budget.get("ceilings")
    baseline = budget.get("baseline_observation")
    if not isinstance(ceilings, dict) or not isinstance(baseline, dict):
        raise PersistenceBacklogError("budget needs ceilings and baseline_observation objects")
    for field in CEILING_FIELDS:
        ceiling = non_negative_integer(ceilings.get(field), f"ceilings.{field}")
        observed = non_negative_integer(
            baseline.get(field), f"baseline_observation.{field}"
        )
        if observed > ceiling:
            raise PersistenceBacklogError(
                f"baseline_observation.{field} exceeds its ceiling"
            )
    baseline_accepted = non_negative_integer(
        baseline.get("accepted_requests"), "baseline_observation.accepted_requests"
    )
    if baseline_accepted != FIXTURE["requests_attempted"]:
        raise PersistenceBacklogError(
            "baseline_observation.accepted_requests must equal requests_attempted"
        )
    baseline_applied = non_negative_integer(
        baseline.get("applied_version"), "baseline_observation.applied_version"

View on GitHub (pinned to 433685b202)