{"record":{"id":"71c3712a50dc2f3c","repo":"NousResearch/hermes-agent","slug":"codex-auxiliary-responses-stream-did-not-return-a","errorCode":null,"errorMessage":"Codex auxiliary Responses stream did not return a final response","messagePattern":"Codex auxiliary Responses stream did not return a final response","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"agent/auxiliary_client.py","lineNumber":1817,"sourceCode":"                    final = event_stream\n                else:\n                    final = _consume_codex_event_stream(\n                        event_stream,\n                        model=str(resp_kwargs.get(\"model\") or model),\n                        on_event=_on_each_event,\n                    )\n            finally:\n                close_fn = getattr(event_stream, \"close\", None)\n                if callable(close_fn):\n                    try:\n                        close_fn()\n                    except Exception:\n                        pass\n                with attempt_stream_lock:\n                    attempt_stream.clear()\n\n            if final is None:\n                raise RuntimeError(\"Codex auxiliary Responses stream did not return a final response\")\n\n            # Extract text and tool calls from the Responses output.\n            # Items may be SimpleNamespace (raw-event path) or dicts\n            # (some legacy fallback paths), so handle both shapes.\n            def _item_get(obj: Any, key: str, default: Any = None) -> Any:\n                val = getattr(obj, key, None)\n                if val is None and isinstance(obj, dict):\n                    val = obj.get(key, default)\n                return val if val is not None else default\n\n            for item in (getattr(final, \"output\", None) or []):\n                item_type = _item_get(item, \"type\")\n                if item_type == \"message\":\n                    for part in (_item_get(item, \"content\") or []):\n                        ptype = _item_get(part, \"type\")\n                        if ptype in {\"output_text\", \"text\"}:\n                            text_parts.append(_item_get(part, \"text\", \"\"))\n                elif item_type == \"function_call\":","sourceCodeStart":1799,"sourceCodeEnd":1835,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/agent/auxiliary_client.py#L1799-L1835","documentation":"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.","triggerScenarios":"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`.","commonSituations":"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.","solutions":["Retry the call — transient truncation usually succeeds on a second attempt","Upgrade to the current release so event-shape handling matches the live API","Check gateway/proxy idle timeouts that may close SSE connections early","If persistent, capture debug logs of the received event sequence to identify the truncation point"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"for attempt in range(2):\n    try:\n        return stream_codex_auxiliary(...)\n    except RuntimeError as e:\n        if \"did not return a final response\" in str(e) and attempt == 0:\n            continue  # truncated stream — retry once on a fresh connection\n        raise","preventionTips":["Retry truncated streams once before escalating — usually transient","Keep hermes updated so Responses-API event-shape handling matches the live API","Raise proxy/gateway SSE idle timeouts if streams are cut before response.completed"],"tags":["codex","streaming","auxiliary","responses-api"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}