HKUDS/Vibe-Trading · error · ValueError
payload must not set reserved chain fields: {sorted(reserved
Error message
payload must not set reserved chain fields: {sorted(reserved_used)} What it means
append_record refuses payloads containing chain-managed fields (seq, prev_hash, hash, etc., i.e. _CHAIN_FIELDS). These are computed by the ledger itself; letting callers set them would break the hash chain's integrity model.
Source
Thrown at agent/src/governance/ledger.py:410
directory the first time the file is created (default ``True``,
matching ``TraceWriter``'s per-record durability guarantee — see
module docstring for why the compliance ledger did not have this
before). ``False`` issues no fsync syscalls at all.
dir_mode: Permission bits for the parent directory when created.
Returns:
The full record as written: ``payload`` merged with ``seq``,
``prev_record_hash``, ``record_hash``.
Raises:
ValueError: ``payload`` sets a reserved chain-field key.
LedgerCorruptionError: The ledger's existing chain is already broken
(a prior record was edited or deleted) — the append is refused
rather than silently extended on top of unknown history.
"""
reserved_used = _CHAIN_FIELDS & payload.keys()
if reserved_used:
raise ValueError(f"payload must not set reserved chain fields: {sorted(reserved_used)}")
path.parent.mkdir(parents=True, exist_ok=True, mode=dir_mode)
created = not path.exists()
handle = open(path, "a+b")
try:
_lock_exclusive(handle)
try:
handle.seek(0)
existing_text = handle.read().decode("utf-8")
# Sealed segments come first: after rotate_if_needed the active
# file starts partway through the chain, and walking it as if it
# began at genesis would report every rotated ledger as corrupt.
# Continuing from the newest segment is also what makes deleting a
# whole segment leave a detectable seam.
start_seq, start_prev = 1, GENESIS_PREV_HASH
segments = archive_segments(path)
if segments:View on GitHub (pinned to 80ffdda44c)
Solutions
- Strip reserved keys before appending: {k: v for k, v in payload.items() if k not in _CHAIN_FIELDS}
- Re-read the ledger API docs — chain fields are outputs, never inputs
- Add a helper that sanitizes replayed records
Example fix
# before
append_record(path, payload=dict(old_record)) # old_record has seq/prev_hash/hash
# after
reserved = {"seq", "prev_hash", "hash", "record_hash"}
append_record(path, payload={k: v for k, v in old_record.items() if k not in reserved}) Defensive patterns
Strategy: validation
Validate before calling
payload = {k: v for k, v in payload.items() if k not in _CHAIN_FIELDS} Type guard
def is_appendable_payload(payload: dict, chain_fields: set) -> bool:
return not (chain_fields & payload.keys()) Try / catch
except ValueError as e: if 'reserved chain fields' in str(e): strip the listed keys and retry append_record
Prevention
- Never feed read-back records into append_record unfiltered
- Wrap append_record with a sanitizing helper
- Treat chain fields as read-only outputs
When it happens
Trigger: Calling append_record(path, payload={..., "seq": 6}) or including prev_hash/hash/record_hash keys in the payload dict.
Common situations: Round-tripping a read record straight back into append_record without stripping chain fields; building payloads from templates that include chain metadata.
Related errors
- {verification.first_break}
- max_bytes must be positive, got {max_bytes}
- {result.first_break}
- invalid alpha_id
- alpha_id not found
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/0de5ff2b1dcd65f9.
Report an issue: GitHub.