Hmbown/CodeWhale · error · PersistenceBacklogError
budget document_kind must be
Error message
budget document_kind must be {BUDGET_KIND} What it means
validate_budget rejects a budget JSON whose document_kind is not exactly "codewhale.persistence_backlog_budget" (the BUDGET_KIND constant). The kind field identifies the JSON document type; the checker refuses any file at the budget path that is not a persistence backlog budget. This guards against pointing --budget at a receipt or unrelated JSON document.
Solutions
- Set "document_kind": "codewhale.persistence_backlog_budget" in the budget JSON
- Verify you passed the budget file, not a receipt, to --budget
- Regenerate or restore the budget file from version control if it was corrupted
Example fix
// before
{ "document_kind": "codewhale.persistence_backlog_receipt", ... }
// after
{ "document_kind": "codewhale.persistence_backlog_budget", ... } Defensive patterns
Strategy: validation
Validate before calling
budget = json.load(open("scripts/persistence-backlog-budget.json"))
assert budget.get("document_kind") == "codewhale.persistence_backlog_budget", "wrong document at budget path" Type guard
def is_budget(doc):
return isinstance(doc, dict) and doc.get("document_kind") == "codewhale.persistence_backlog_budget" Try / catch
try:
validate_budget(budget)
except PersistenceBacklogError as e:
if "document_kind must be" in str(e):
print("check the --budget path: you may have passed a receipt file")
raise Prevention
- Keep receipts and budgets in clearly named files and never swap their paths
- Validate document_kind right after loading any JSON document
- Use the default BUDGET_PATH instead of ad-hoc --budget overrides when possible
When it happens
Trigger: compare calls validate_budget on a budget dict loaded from the --budget path (default scripts/persistence-backlog-budget.json) whose document_kind is missing, misspelled, or set to another kind (e.g. a receipt's document_kind).
Common situations: Passing a receipt file to --budget; renaming or re-keying document_kind while editing the budget; copying an old template before the kind identifier was introduced.
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
- agent profile provider cannot be empty
- agent profile provider must be a simple provider id
- api_key cannot be empty string
- approval_policy ' ' is not allowed by requirements ( )
- baseline_observation.accepted_requests must equal…
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/c0d242dbc1a0db3b.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/check-persistence-backlog-budget.py:244
if receipt["rss_supported"]:
for field in rss_fields:
non_negative_integer(receipt[field], field)
before = receipt["rss_before_bytes"]
if receipt["rss_during_delta_bytes"] != max(
0, receipt["rss_during_bytes"] - before
):
raise PersistenceBacklogError("rss_during_delta_bytes is inconsistent")
if receipt["rss_after_delta_bytes"] != max(
0, receipt["rss_after_bytes"] - before
):
raise PersistenceBacklogError("rss_after_delta_bytes is inconsistent")
elif any(receipt[field] is not None for field in rss_fields):
raise PersistenceBacklogError("unsupported RSS fields must be null")
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}")View on GitHub (pinned to 433685b202)