Hmbown/CodeWhale · error · RuntimeContractError
field ` ` must match the owned sorted tool_names
Error message
{kind} field `{'.'.join((*base, 'identity_sha256'))}` must match the owned sorted tool_names What it means
Each mode/surface section stores identity_sha256, the SHA-256 of its sorted tool_names joined with NUL bytes (see tool_identity_digest). If the stored digest does not match the recomputed value, the section's tool list was altered after signing or the digest was computed differently.
Solutions
- Recompute the digest with hashlib.sha256("\0".join(sorted(set(names))).encode()).hexdigest() and store it
- Regenerate the receipt with the current script so list and digest are consistent
- Ensure any external generator replicates the exact NUL-joined sorted-name hashing scheme
Example fix
# before (stale digest)
"identity_sha256": "aaa..."
# after
import hashlib
"identity_sha256": hashlib.sha256("\0".join(names).encode()).hexdigest() Defensive patterns
Strategy: validation
Validate before calling
import hashlib
names = sorted(set(section["tool_names"]))
expected = hashlib.sha256("\0".join(names).encode("utf-8")).hexdigest()
assert section["identity_sha256"] == expected Try / catch
try:
validate_receipt(receipt)
except RuntimeContractError as e:
if "must match the owned sorted tool_names" in str(e):
print("stale identity digest; regenerate the receipt")
raise Prevention
- Compute the digest in the same function that writes tool_names
- Never copy digests between catalog states
- Mirror the exact NUL-join hashing scheme in any external generator
When it happens
Trigger: validate_identity_structure recomputes tool_identity_digest(names) and finds it differs from the stored tool_catalog.modes.<mode>.<surface>.identity_sha256.
Common situations: tool_names edited without recomputing the digest; digest computed over unsorted or differently joined names by a custom generator; receipt copied from a different catalog state.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- Codewhale metadata event was not a terminal receipt
- Codewhale terminal receipt omitted a valid
- field ` ` must be sorted unique non-empty strings
- is missing required field
- metric ` ` must equal the owned tool_names length ( )
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/278c6ca765f215bb.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/check-runtime-contract-budget.py:241
dotted_names = ".".join((*base, "tool_names"))
if (
not isinstance(names, list)
or any(not isinstance(name, str) or not name for name in names)
or names != sorted(set(names))
):
raise RuntimeContractError(
f"{kind} field `{dotted_names}` must be sorted unique non-empty strings"
)
count = metric_value(document, (*base, "tools"), kind)
if count != len(names):
raise RuntimeContractError(
f"{kind} metric `{'.'.join((*base, 'tools'))}` must equal the "
f"owned tool_names length ({len(names)})"
)
digest = required_value(document, (*base, "identity_sha256"), kind)
expected = tool_identity_digest(names)
if digest != expected:
raise RuntimeContractError(
f"{kind} field `{'.'.join((*base, 'identity_sha256'))}` must "
"match the owned sorted tool_names"
)
for stage, _label in REPRESENTATIVE_STAGES:
path = ("representative_context", "stages", stage, "identity_sha256")
digest = required_value(document, path, kind)
if not isinstance(digest, str) or re.fullmatch(r"[0-9a-f]{64}", digest) is None:
raise RuntimeContractError(
f"{kind} field `{'.'.join(path)}` must be a lowercase SHA-256 digest"
)
def validate_receipt(receipt: dict[str, Any]) -> None:
validate_document(receipt, RECEIPT_KIND, "receipt")
skill_discovery = receipt.get("skill_discovery")
identical = (
skill_discovery.get("prompts_byte_identical")View on GitHub (pinned to 433685b202)