Posted in ai
157
1:07 am, May 27, 2026
 

bug fix for hermes agent - Error: 'NoneType' object is not iterable

<p>After the latest hermes update i was getting this error:</p>
<p><!-- obsidian --></p>
<p>API call failed (attempt 1/3): TypeError<br />🔌 Provider: openai-codex Model: gpt-5.5<br />🌐 Endpoint: <a class="external-link" href="https://chatgpt.com/backend-api/codex" target="blank" rel="noopener nofollow">https://chatgpt.com/backend-api/codex</a><br />📝 Error: 'NoneType' object is not iterable<br />⚠️ Non-retryable error (HTTP None) &mdash; trying fallback...<br />❌ Non-retryable error (HTTP None): 'NoneType' object is not iterable<br />❌ Non-retryable client error (HTTP None). Aborting.<br />🔌 Provider: openai-codex Model: gpt-5.5<br />🌐 Endpoint: <a class="external-link" href="https://chatgpt.com/backend-api/codex" target="blank" rel="noopener nofollow">https://chatgpt.com/backend-api/codex</a><br />💡 This type of error won't be fixed by retrying.</p>
<p>I found the bug reported here:</p>
<p><a href="https://github.com/NousResearch/hermes-agent/issues/32894">https://github.com/NousResearch/hermes-agent/issues/32894</a></p>
<p>As the patch is not official yet, codex seemed to be able to patch it. i got codex to output a document of the changes below.&nbsp;</p>
<p>&nbsp;</p>

HTML

# Codex Responses Stream Output Fix

Date: 2026-05-27

Sensitive-data note: this write-up omits credentials, raw request data, account identifiers, local paths, and environment-specific values.

## Summary

Hermes was patched to tolerate a Codex Responses API edge case where the SDK stream parser or response convenience accessors could fail when the final response had missing, empty, or `None` output.

The visible failure was a `TypeError` like:

```text
'NoneType' object is not iterable
```

The underlying problem was that Hermes had already received useful streamed events, such as text deltas, reasoning deltas, or completed output items, but the SDK final response could still expose `output=None`, `output=[]`, or a broken `output_text` accessor. That made the conversation loop treat the response as invalid, crash while reading `output_text`, or lose streamed content that had already arrived.

## Files Patched

- `agent/codex_runtime.py`
- `agent/codex_responses_adapter.py`
- `agent/conversation_loop.py`
- `tests/run_agent/test_run_agent_codex_responses.py`
- `tests/agent/transports/test_codex_transport.py`

## Runtime Patch

### `agent/codex_runtime.py`

Added shared stream recovery helpers:

- `_backfill_codex_response_output(...)`
- `_synthesize_codex_response_from_stream(...)`

These helpers reconstruct usable response output from stream events that were already observed before the SDK returned an incomplete final response or raised a parser error.

The backfill behavior now handles three cases:

1. If completed output items were streamed, copy them onto `response.output`.
2. If text deltas were streamed and no tool calls were present, synthesize a completed assistant message output item.
3. If only reasoning deltas were streamed, synthesize a reasoning output item and mark the response incomplete so Hermes continues correctly instead of treating reasoning-only output as a final answer.

The primary stream path now collects reasoning deltas as well as completed output items and text deltas. If the SDK stream parser raises `TypeError("'NoneType' object is not iterable")`, Hermes falls back to `responses.create(stream=True)`. If that fallback also fails, Hermes can still return a synthesized incomplete response from the stream data already collected.

The fallback `create(stream=True)` path was also updated to:

- collect reasoning deltas,
- detect function-call events,
- avoid synthesizing plain text output when tool calls are involved,
- backfill terminal responses whose output is missing or empty,
- synthesize a recoverable incomplete response if the stream ends without a terminal response but useful deltas were received.

## Response Normalization Patch

### `agent/codex_responses_adapter.py`

Added `_safe_response_output_text(response)`.

The OpenAI SDK `response.output_text` convenience accessor can itself raise when the underlying output structure is malformed or missing. Hermes now reads it behind a guard:

- returns stripped text when available,
- logs a debug message when access fails,
- returns an empty string instead of letting normalization crash.

Normalization now uses this safe accessor in both places where `output_text` is used as a fallback.

The finish-reason logic was also tightened so reasoning-only responses are marked `incomplete` when there is no final visible text. This applies whether the reasoning came from raw reasoning items or extracted reasoning summary text.

## Conversation Loop Patch

### `agent/conversation_loop.py`

The validation fallback that checks `response.output_text` now catches accessor failures. This prevents the conversation loop from crashing while trying to decide whether a response with empty output can still be recovered from `output_text`.

## Tests Added

### `tests/run_agent/test_run_agent_codex_responses.py`

Added coverage for the stream parser failure path:

- primary `responses.stream(...)` emits reasoning and then raises `TypeError("'NoneType' object is not iterable")`;
- Hermes falls back to `responses.create(stream=True)`;
- fallback stream emits reasoning with a completed response whose output is `None`;
- Hermes backfills a reasoning output item instead of crashing or returning unusable output.

### `tests/agent/transports/test_codex_transport.py`

Added coverage for normalization when:

- the response contains only reasoning output,
- the SDK `output_text` property raises `TypeError("'NoneType' object is not iterable")`,
- Hermes preserves the reasoning text and marks the normalized response as `incomplete`.

## Verification

Targeted test command:

```bash
venv/bin/pytest tests/run_agent/test_run_agent_codex_responses.py tests/agent/transports/test_codex_transport.py
```

Result:

```text
112 passed, 1 warning in 27.10s
```

The warning was an unrelated Python `audioop` deprecation warning from `discord/player.py`.

## Practical Effect

After this patch, Hermes is more resilient to malformed or partially populated Codex Responses API final responses. It can recover from streamed events that were already received, avoid SDK `output_text` crashes, preserve reasoning-only responses as incomplete turns, and continue the agent loop instead of failing on a `None` output structure.

Codex Responses Stream Output Fix

Date: 2026-05-27

Sensitive-data note: this write-up omits credentials, raw request data, account identifiers, local paths, and environment-specific values.

Summary

Hermes was patched to tolerate a Codex Responses API edge case where the SDK stream parser or response convenience accessors could fail when the final response had missing, empty, or None output.

The visible failure was a TypeError like:

'NoneType' object is not iterable

The underlying problem was that Hermes had already received useful streamed events, such as text deltas, reasoning deltas, or completed output items, but the SDK final response could still expose output=None, output=[], or a broken outputtext accessor. That made the conversation loop treat the response as invalid, crash while reading outputtext, or lose streamed content that had already arrived.

Files Patched

    - agent/codexruntime.py
  • agent/codexresponsesadapter.py
  • agent/conversationloop.py
  • tests/runagent/testrunagentcodexresponses.py
  • tests/agent/transports/testcodextransport.py

Runtime Patch

agent/codexruntime.py

Added shared stream recovery helpers:

    - backfillcodexresponseoutput(...)
  • synthesizecodexresponsefromstream(...)

These helpers reconstruct usable response output from stream events that were already observed before the SDK returned an incomplete final response or raised a parser error.

The backfill behavior now handles three cases:

1. If completed output items were streamed, copy them onto response.output.
2. If text deltas were streamed and no tool calls were present, synthesize a completed assistant message output item.
3. If only reasoning deltas were streamed, synthesize a reasoning output item and mark the response incomplete so Hermes continues correctly instead of treating reasoning-only output as a final answer.

The primary stream path now collects reasoning deltas as well as completed output items and text deltas. If the SDK stream parser raises TypeError("'NoneType' object is not iterable"), Hermes falls back to responses.create(stream=True). If that fallback also fails, Hermes can still return a synthesized incomplete response from the stream data already collected.

The fallback create(stream=True) path was also updated to:

    - collect reasoning deltas,
  • detect function-call events,
  • avoid synthesizing plain text output when tool calls are involved,
  • backfill terminal responses whose output is missing or empty,
  • synthesize a recoverable incomplete response if the stream ends without a terminal response but useful deltas were received.

Response Normalization Patch

agent/codexresponsesadapter.py

Added saferesponseoutputtext(response).

The OpenAI SDK response.outputtext convenience accessor can itself raise when the underlying output structure is malformed or missing. Hermes now reads it behind a guard:

    - returns stripped text when available,
  • logs a debug message when access fails,
  • returns an empty string instead of letting normalization crash.

Normalization now uses this safe accessor in both places where outputtext is used as a fallback.

The finish-reason logic was also tightened so reasoning-only responses are marked incomplete when there is no final visible text. This applies whether the reasoning came from raw reasoning items or extracted reasoning summary text.

Conversation Loop Patch

agent/conversationloop.py

The validation fallback that checks response.outputtext now catches accessor failures. This prevents the conversation loop from crashing while trying to decide whether a response with empty output can still be recovered from outputtext.

Tests Added

tests/runagent/testrunagentcodexresponses.py

Added coverage for the stream parser failure path:

    - primary responses.stream(...) emits reasoning and then raises TypeError("'NoneType' object is not iterable");
  • Hermes falls back to responses.create(stream=True);
  • fallback stream emits reasoning with a completed response whose output is None;
  • Hermes backfills a reasoning output item instead of crashing or returning unusable output.

tests/agent/transports/testcodextransport.py

Added coverage for normalization when:

    - the response contains only reasoning output,
  • the SDK outputtext property raises TypeError("'NoneType' object is not iterable"),
  • Hermes preserves the reasoning text and marks the normalized response as incomplete.

Verification

Targeted test command:

venv/bin/pytest tests/runagent/testrunagentcodexresponses.py tests/agent/transports/testcodextransport.py

Result:

112 passed, 1 warning in 27.10s

The warning was an unrelated Python audioop deprecation warning from discord/player.py.

Practical Effect

After this patch, Hermes is more resilient to malformed or partially populated Codex Responses API final responses. It can recover from streamed events that were already received, avoid SDK outputtext crashes, preserve reasoning-only responses as incomplete turns, and continue the agent loop instead of failing on a None output structure.

View Statistics
This Week
157
This Month
157
This Year
157

No Items Found.

Add Comment
Type in a Nick Name here
 
Search Code
Search Code by entering your search text above.
Welcome

This is my test area for webdev. I keep a collection of code here, mostly for my reference. Also if i find a good link, i usually add it here and then forget about it. more...

You could also follow me on twitter. I have a couple of youtube channels if you want to see some video related content. RuneScape 3, Minecraft and also a coding channel here Web Dev.

If you found something useful or like my work, you can buy me a coffee here. Mmm Coffee. ☕

❤️👩‍💻🎮

🪦 2000 - 16 Oct 2022 - Boots
Random Quote


Latest News
## 🚀 AI Giants Hit Bullseye: Anthropic & OpenAI Achieve Product-Market Fit Anthropic and OpenAI have reached a significant milestone, finding product-market fit with their AI technologies, which means their products effectively meet the needs of their customers, driving growth and adoption. This achievement showcases the practical value of their innovations, enabling businesses and individuals to leverage AI for enhanced productivity and efficiency. With this alignment of product and market needs, these companies are poised to transform industries and shape the future of technology.