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
- Add/restore both "ceilings" and "baseline_observation" as JSON objects in the budget
- Regenerate the budget from the measurement pipeline to get a complete document
- 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
- Validate budget JSON structure after every edit or merge
- Regenerate the budget wholesale rather than splicing sections by hand
- Keep both sections present when migrating between schema versions
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
- baseline_observation.accepted_requests must equal…
- baseline_observation.
- budget baseline_receipt path changed
- budget document_kind must be
- budget fixture. must remain
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)