Hmbown/CodeWhale · error · RuntimeError

Codewhale terminal metadata did not immediately precede done

Error message

Codewhale terminal metadata did not immediately precede done

What it means

The terminal metadata receipt must be the event immediately preceding the single done event (ordered_types[-2:-1] == ['metadata']). This error means something else sat between the metadata event and done — e.g. a content or error event after the receipt — or metadata appeared only early in the stream.

Source

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

        event_type = event.get("type")
        if event_type not in _EVENT_TYPES:
            raise RuntimeError("Codewhale stream-json contained an unknown event type")
        counts[event_type] += 1
        ordered_types.append(event_type)
        if event_type == "metadata":
            if terminal is not None:
                raise RuntimeError("Codewhale emitted more than one terminal metadata receipt")
            meta = event.get("meta")
            if not isinstance(meta, dict) or meta.get("receipt_kind") != "terminal":
                raise RuntimeError("Codewhale metadata event was not a terminal receipt")
            terminal = _bounded_terminal(meta)

    if terminal is None:
        raise RuntimeError("Codewhale stream-json omitted terminal metadata")
    if counts["done"] != 1 or not ordered_types or ordered_types[-1] != "done":
        raise RuntimeError("Codewhale stream-json did not end with exactly one done event")
    if ordered_types[-2:-1] != ["metadata"]:
        raise RuntimeError("Codewhale terminal metadata did not immediately precede done")
    for field in ["binary_sha256", "prompt_sha256"]:
        if not isinstance(terminal.get(field), str) or not _SHA256.fullmatch(
            terminal[field]
        ):
            raise RuntimeError(f"Codewhale terminal receipt omitted a valid {field}")
    return {
        "schema": STREAM_SCHEMA,
        "schema_version": STREAM_SCHEMA_VERSION,
        "events": dict(sorted(counts.items())),
        "terminal": terminal,
    }

View on GitHub (pinned to 8880682c63)

Solutions

  1. Check the last three event types in stdout; the required tail is exactly metadata, done.
  2. Move any post-receipt output (final answer text, diagnostics) before the metadata event or into the metadata/done payload.
  3. Ensure the facade emits terminal metadata as the penultimate event right before done, once.
  4. Pin to the supported Codewhale release if the skew comes from an untested build.

Example fix

# before: content emitted after the terminal receipt
emit_metadata(...)
emit({"type": "content", "text": final_answer})
emit_done()

# after: content precedes the receipt
emit({"type": "content", "text": final_answer})
emit_metadata(...)
emit_done()
Defensive patterns

Strategy: validation

Validate before calling

def terminal_precedes_done(stdout: str) -> bool:
    types = [
        json.loads(line).get("type")
        for line in stdout.splitlines()
        if line.strip()
    ]
    return types[-2:-1] == ["metadata"] and types[-1] == "done"

Prevention

When it happens

Trigger: A facade emits terminal metadata, then an extra 'content'/'error' event, then done; or emits metadata early and never again, with other events in between. Both violate the strict two-line terminal framing the harness enforces.

Common situations: Binaries that print the receipt and then a final answer line; wrappers appending diagnostics after the receipt; partial implementations that send metadata at session start rather than at termination.

Related errors


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