mercredi 27 mai 2026 à 00:44

Co-fondatrice de Pinstrap. J’aime les pixels bien placés, les mots bien sentis, et les concepts qui laissent une trace (dans la tête, pas dans l’atmosphère). Dotée d'un humour indéniablement violent, je vulgarise les sujets complexes pour que chacun, même le plus éclaté, comprenne les sujets relatifs à la com'/ marketing/ design/ tech etc. En gros je vous facilite la vie et vos projets de fac ou d'école de commerce.

# Hermes OpenAI Codex NoneType Stream Crash Hotfix
Date: 2026-05-27
This write-up documents a production hotfix for a Hermes Agent crash observed when
using the OpenAI Codex provider through the Responses streaming API.
The upstream tracking issue is:
https://github.com/NousResearch/hermes-agent/issues/32883
## Summary
Hermes can crash during an OpenAI Codex streaming response with:
text</p><p>TypeError: 'NoneType' object is not iterable</p><p>
In our case, the error occurred while Writer-Docx invoked Hermes as an enrichment
provider. Hermes created a session successfully, but exited with code 1 before
returning the expected JSON payload. The application then marked the enrichment
run as failed because the provider output could not be normalized.
The application-level failure was:
text</p><p>Natural risks provider output did not match the required JSON contract.</p><p>
The real root cause was lower-level:
text</p><p>Error: 'NoneType' object is not iterable</p><p>
## Environment Observed
The issue was reproduced on:
text</p><p>Hermes Agent v0.14.0</p><p>Commit: bb4703c76</p><p>Provider: openai-codex</p><p>Model: gpt-5.5</p><p>Platform: Ubuntu 24.04 arm64</p><p>
The same crash also reproduced with other Codex models, including:
text</p><p>gpt-5.4-mini</p><p>gpt-5.3-codex</p><p>
That confirmed the issue was not specific to the model or the application prompt.
## Minimal Reproduction
Run a minimal Hermes prompt using the affected profile:
bash</p><p>hermes -p geo2mo-natural-risks chat -Q \</p><p> --source writer-docx-debug \</p><p> -q "Return only {\"ok\":true}."</p><p>
Before the hotfix, this failed with:
text</p><p>Error: 'NoneType' object is not iterable</p><p>session_id: ...</p><p>
After the hotfix, it returned:
json</p><p>{"ok":true}</p><p>
## Root Cause
The OpenAI Codex Responses stream can emit useful stream deltas, then finish with
a final response object whose output is missing or None.
The OpenAI SDK stream helper may then try to iterate over response.output,
raising:
text</p><p>TypeError: 'NoneType' object is not iterable</p><p>
Hermes treated this as a non-retryable client error, so the process exited before
the caller received a final assistant message.
The upstream issue explains the same failure mode and proposes recovery by:
- backfilling missing response output from streamed output items;
- synthesizing message output from streamed text deltas;
- preserving reasoning-only deltas as an incomplete response;
- falling back to responses.create(stream=True) when the SDK stream parser
crashes;
- guarding response.output_text access because that convenience accessor can
also raise on malformed or partial output.
## Patch Scope
The hotfix modified three Hermes files:
text</p><p>/usr/local/lib/hermes-agent/agent/codex_<a target="_blank" rel="noopener noreferrer nofollow" href="http://runtime.py">runtime.py</a></p><p>/usr/local/lib/hermes-agent/agent/codex_responses_<a target="_blank" rel="noopener noreferrer nofollow" href="http://adapter.py">adapter.py</a></p><p>/usr/local/lib/hermes-agent/agent/conversation_<a target="_blank" rel="noopener noreferrer nofollow" href="http://loop.py">loop.py</a></p><p>
The patch is intentionally narrow. It does not change model selection, auth,
prompt construction, tool schemas, or application code.
## Patch Behavior
### 1. Backfill Missing Responses Output
When the final Responses object has no usable output, the patch attempts to
reconstruct it from data already seen in the stream:
- completed response.output_item.done items;
- response.output_text.delta chunks;
- reasoning deltas.
If text deltas exist and no tool call is active, the patch synthesizes a normal
assistant message output item.
If only reasoning exists, the patch synthesizes a reasoning output item and marks
the response as incomplete so Hermes can continue normally.
### 2. Catch the SDK Parser Crash
The main stream loop catches:
text</p><p>'NoneType' object is not iterable</p><p>
When this exact SDK failure happens, Hermes falls back to:
python</p><p>responses.create(stream=True)</p><p>
If that fallback also cannot produce a terminal response, Hermes attempts to
recover from the deltas collected before the crash.
### 3. Guard response.output_text
Some SDK convenience accessors can raise while trying to derive text from a
partial or malformed response. The patch wraps response.output_text reads in a
safe helper and returns an empty string on accessor failure.
### 4. Treat Reasoning-Only Responses as Incomplete
When a response contains reasoning but no final user-visible text, the patch
marks it as incomplete. This avoids sending Hermes into an empty-output failure
path and allows the normal continuation loop to ask for the final answer.
## Deployment Procedure
### 1. Back Up the Existing Hermes Files
bash</p><p>ssh IA</p><p>cd /usr/local/lib/hermes-agent</p><p>ts=$(date -u +%Y%m%dT%H%M%SZ)</p><p>mkdir -p /root/hermes-hotfix-backups/$ts</p><p>cp agent/codex_<a target="_blank" rel="noopener noreferrer nofollow" href="http://runtime.py">runtime.py</a> \</p><p> agent/codex_responses_<a target="_blank" rel="noopener noreferrer nofollow" href="http://adapter.py">adapter.py</a> \</p><p> agent/conversation_<a target="_blank" rel="noopener noreferrer nofollow" href="http://loop.py">loop.py</a> \</p><p> /root/hermes-hotfix-backups/$ts/</p><p>
### 2. Apply the Hotfix
Apply the patch from the upstream issue to these files:
text</p><p>agent/codex_<a target="_blank" rel="noopener noreferrer nofollow" href="http://runtime.py">runtime.py</a></p><p>agent/codex_responses_<a target="_blank" rel="noopener noreferrer nofollow" href="http://adapter.py">adapter.py</a></p><p>agent/conversation_<a target="_blank" rel="noopener noreferrer nofollow" href="http://loop.py">loop.py</a></p><p>
If applying manually, verify the following symbols exist afterward:
bash</p><p>cd /usr/local/lib/hermes-agent</p><p>rg "_safe_response_output_text|_backfill_codex_response_output|stream_parser_recovered_none_output|output_text access failed during validation" \</p><p> agent/codex_<a target="_blank" rel="noopener noreferrer nofollow" href="http://runtime.py">runtime.py</a> \</p><p> agent/codex_responses_<a target="_blank" rel="noopener noreferrer nofollow" href="http://adapter.py">adapter.py</a> \</p><p> agent/conversation_<a target="_blank" rel="noopener noreferrer nofollow" href="http://loop.py">loop.py</a></p><p>
Expected matches:
text</p><p>agent/codex_responses_<a target="_blank" rel="noopener noreferrer nofollow" href="http://adapter.py">adapter.py</a>:_safe_response_output_text</p><p>agent/codex_<a target="_blank" rel="noopener noreferrer nofollow" href="http://runtime.py">runtime.py</a>:_backfill_codex_response_output</p><p>agent/codex_<a target="_blank" rel="noopener noreferrer nofollow" href="http://runtime.py">runtime.py</a>:stream_parser_recovered_none_output</p><p>agent/conversation_<a target="_blank" rel="noopener noreferrer nofollow" href="http://loop.py">loop.py</a>:output_text access failed during validation</p><p>
### 3. Compile Check
bash</p><p>cd /usr/local/lib/hermes-agent</p><p>venv/bin/python -m py_compile \</p><p> agent/codex_<a target="_blank" rel="noopener noreferrer nofollow" href="http://runtime.py">runtime.py</a> \</p><p> agent/codex_responses_<a target="_blank" rel="noopener noreferrer nofollow" href="http://adapter.py">adapter.py</a> \</p><p> agent/conversation_<a target="_blank" rel="noopener noreferrer nofollow" href="http://loop.py">loop.py</a></p><p>
### 4. Save the Patch for Audit and Rollback
bash</p><p>cd /usr/local/lib/hermes-agent</p><p>git diff -- \</p><p> agent/codex_<a target="_blank" rel="noopener noreferrer nofollow" href="http://runtime.py">runtime.py</a> \</p><p> agent/codex_responses_<a target="_blank" rel="noopener noreferrer nofollow" href="http://adapter.py">adapter.py</a> \</p><p> agent/conversation_<a target="_blank" rel="noopener noreferrer nofollow" href="http://loop.py">loop.py</a> \</p><p> > /root/hermes-hotfix-backups/$ts/issue-32883-hotfix.patch</p><p>
### 5. Restart Long-Running Hermes Processes If Needed
If Hermes is only invoked as a CLI subprocess, new invocations will load the
patched files automatically.
If a Hermes gateway or daemon is running, restart it using the service manager
used on your host. For example, inspect service names first:
bash</p><p>systemctl --user list-units | grep -i hermes</p><p>
Then restart the relevant Hermes gateway service.
## Validation
Run the minimal prompt again:
bash</p><p>env HERMES_NO_COLOR=1 NO_COLOR=1 TERM=dumb \</p><p> hermes -p geo2mo-natural-risks chat -Q \</p><p> --source writer-docx-debug \</p><p> -q "Return only {\"ok\":true}."</p><p>
Expected result:
json</p><p>{"ok":true}</p><p>
The Hermes error log may still contain old failures. What matters is that the
new run exits with status 0 and returns the expected content.
You may also see a new warning similar to:
text</p><p>Codex Responses stream parser failed on missing output; falling back to create(stream=True).</p><p>
That warning is expected after the hotfix. It means the patch detected the SDK
stream failure and recovered through the fallback path.
## Application-Level Validation
For Writer-Docx, the original failed enrichment run had:
text</p><p>provider_key: hermes</p><p>collector_key: natural-risks</p><p>status: failed</p><p>error: Natural risks provider output did not match the required JSON contract.</p><p>raw stderr: Error: 'NoneType' object is not iterable</p><p>
After the Hermes hotfix:
1. Keep the web app and enrichment worker running.
2. Retry the failed enrichment from the UI.
3. Confirm the worker processes a new run.
4. Inspect the run output.
If the next failure is about JSON shape, source retrieval, or domain-specific QC,
the transport bug is fixed and the remaining issue belongs to the agent output
contract or the collector logic.
## Rollback
Restore the backed-up files:
bash</p><p>ssh IA</p><p>backup_dir=/root/hermes-hotfix-backups/20260527T003104Z</p><p>cd /usr/local/lib/hermes-agent</p><p>cp "$backup_dir/codex_<a target="_blank" rel="noopener noreferrer nofollow" href="http://runtime.py">runtime.py</a>" agent/codex_<a target="_blank" rel="noopener noreferrer nofollow" href="http://runtime.py">runtime.py</a></p><p>cp "$backup_dir/codex_responses_<a target="_blank" rel="noopener noreferrer nofollow" href="http://adapter.py">adapter.py</a>" agent/codex_responses_<a target="_blank" rel="noopener noreferrer nofollow" href="http://adapter.py">adapter.py</a></p><p>cp "$backup_dir/conversation_<a target="_blank" rel="noopener noreferrer nofollow" href="http://loop.py">loop.py</a>" agent/conversation_<a target="_blank" rel="noopener noreferrer nofollow" href="http://loop.py">loop.py</a></p><p>venv/bin/python -m py_compile \</p><p> agent/codex_<a target="_blank" rel="noopener noreferrer nofollow" href="http://runtime.py">runtime.py</a> \</p><p> agent/codex_responses_<a target="_blank" rel="noopener noreferrer nofollow" href="http://adapter.py">adapter.py</a> \</p><p> agent/conversation_<a target="_blank" rel="noopener noreferrer nofollow" href="http://loop.py">loop.py</a></p><p>
Restart Hermes daemons or gateways if your deployment keeps Hermes loaded in a
long-running process.
## Operational Notes
- This is a hotfix against a global Hermes installation. Keep the backup until
the upstream patch is merged and deployed.
- A future hermes update may overwrite the local patch.
- After upstream includes the fix, prefer returning to a clean upstream checkout.
- Keep the saved patch file so the exact production delta is auditable.
- The hotfix does not change authentication. If Hermes auth is expired, this
patch will not fix auth failures.
## References
- Upstream issue: https://github.com/NousResearch/hermes-agent/issues/32883
- Observed root error: TypeError: 'NoneType' object is not iterable
- Observed Hermes version: Hermes Agent v0.14.0
- Observed upstream base commit: bb4703c76
Discutons de vos besoins et voyons comment nous pouvons vous accompagner dans la réalisation de vos objectifs.