Hmbown/CodeWhale · error · RuntimeError

Codewhale terminal receipt contained a non-scalar field

Error message

Codewhale terminal receipt contained a non-scalar field

What it means

Every terminal metadata field must be a scalar: a str or an int, with bool explicitly rejected (isinstance(True, int) is true in Python, so the code excludes it via 'not isinstance(value, bool)'). Lists, dicts, floats, and booleans raise RuntimeError while parsing, because the receipt is stored as bounded, deterministic JSON in trace metadata.

Source

Thrown at integrations/verifiers-codewhale/codewhale_harness/harness.py:268

        )
        is not None
    )


def _bounded_terminal(meta: dict[str, Any]) -> dict[str, Any]:
    terminal: dict[str, Any] = {}
    for key in _TERMINAL_FIELDS:
        if key not in meta or meta[key] is None:
            continue
        value = meta[key]
        if isinstance(value, str):
            if len(value) > MAX_TERMINAL_STRING_CHARS:
                raise RuntimeError("Codewhale terminal receipt exceeded its string bound")
        elif isinstance(value, int) and not isinstance(value, bool):
            if value < 0 or value > 2**63 - 1:
                raise RuntimeError("Codewhale terminal receipt contained an invalid count")
        else:
            raise RuntimeError("Codewhale terminal receipt contained a non-scalar field")
        terminal[key] = value
    encoded = json.dumps(terminal, sort_keys=True, separators=(",", ":")).encode()
    if len(encoded) > MAX_TERMINAL_RECEIPT_BYTES:
        raise RuntimeError("Codewhale terminal receipt exceeded its total bound")
    return terminal


def _install_script(version: str) -> str:
    version_q = shlex.quote(version)
    install_q = shlex.quote(INSTALL_DIR)
    release_q = shlex.quote(RELEASE_ROOT)
    return f"""
set -eu
version={version_q}
install_dir={install_q}
release_root={release_q}
if [ "$(uname -s)" != Linux ]; then
    echo "automatic Codewhale installation supports Linux runtimes; set binary_path" >&2

View on GitHub (pinned to 8880682c63)

Solutions

  1. Emit only strings and integers in terminal metadata
  2. Serialize nested data to a compact string, or move it to event types the harness counts but does not store
  3. Coerce floats with int() and map booleans to their string forms before emitting

Example fix

# before
meta = {'input_tokens': 123.0, 'usage': {'total': 123}}
# after
meta = {'input_tokens': 123}
Defensive patterns

Strategy: type-guard

Type guard

def is_scalar(v):
    return isinstance(v, str) or (isinstance(v, int) and not isinstance(v, bool))

meta = {k: v for k, v in raw_meta.items() if is_scalar(v)}

Prevention

When it happens

Trigger: Facades emitting nested objects such as a usage dict; floats for token counts (123.0); JSON true/false for posture or status fields.

Common situations: Facade authors reusing rich API objects as receipts; JSON round-trips turning ints into floats; schema drift adding structured fields.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/9ec42ed8467e531f. Report an issue: GitHub.