NousResearch/hermes-agent · error · RuntimeError

Codex auxiliary Responses stream did not return a final resp

Error message

Codex auxiliary Responses stream did not return a final response

What it means

The Codex auxiliary Responses stream ended normally — no timeout fired, no exception escaped — but produced no final response object: `final` stayed None after draining the event stream. The adapter treats 'stream complete without an answer' as a hard RuntimeError rather than returning empty content, because an auxiliary call with no output is unusable.

Source

Thrown at agent/auxiliary_client.py:1817

                    final = event_stream
                else:
                    final = _consume_codex_event_stream(
                        event_stream,
                        model=str(resp_kwargs.get("model") or model),
                        on_event=_on_each_event,
                    )
            finally:
                close_fn = getattr(event_stream, "close", None)
                if callable(close_fn):
                    try:
                        close_fn()
                    except Exception:
                        pass
                with attempt_stream_lock:
                    attempt_stream.clear()

            if final is None:
                raise RuntimeError("Codex auxiliary Responses stream did not return a final response")

            # Extract text and tool calls from the Responses output.
            # Items may be SimpleNamespace (raw-event path) or dicts
            # (some legacy fallback paths), so handle both shapes.
            def _item_get(obj: Any, key: str, default: Any = None) -> Any:
                val = getattr(obj, key, None)
                if val is None and isinstance(obj, dict):
                    val = obj.get(key, default)
                return val if val is not None else default

            for item in (getattr(final, "output", None) or []):
                item_type = _item_get(item, "type")
                if item_type == "message":
                    for part in (_item_get(item, "content") or []):
                        ptype = _item_get(part, "type")
                        if ptype in {"output_text", "text"}:
                            text_parts.append(_item_get(part, "text", ""))
                elif item_type == "function_call":

View on GitHub (pinned to c896c09c42)

Solutions

  1. Retry the call — transient truncation usually succeeds on a second attempt
  2. Upgrade to the current release so event-shape handling matches the live API
  3. Check gateway/proxy idle timeouts that may close SSE connections early
  4. If persistent, capture debug logs of the received event sequence to identify the truncation point
Defensive patterns

Strategy: retry

Try / catch

for attempt in range(2):
    try:
        return stream_codex_auxiliary(...)
    except RuntimeError as e:
        if "did not return a final response" in str(e) and attempt == 0:
            continue  # truncated stream — retry once on a fresh connection
        raise

Prevention

When it happens

Trigger: A Responses-API stream that closes after only partial events (response.created / in_progress) without a completed final response — upstream truncation, an interrupted session, or an API event-shape change so the terminal event is never matched into `final`.

Common situations: Upstream incident truncating SSE streams; proxy/gateway idle timeout cutting the connection before response.completed; SDK/API version drift renaming the terminal event; empty-output model response on an unusual prompt.

Related errors


AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14). Data as JSON: /api/errors/71c3712a50dc2f3c. Report an issue: GitHub.