Responses Lite: changing reasoning effort can strand a large session on “Request blocked.” until compaction

Open 💬 4 comments Opened Jul 12, 2026 by ignatremizov

What version of Codex CLI is running?

codex-cli 0.144.0, from a custom fork based on current openai/codex source.

The relevant incremental WebSocket and error-handling paths described below are present on upstream main at 9e552e9d15ba52bed7077d5357f3e18e330f8f38.

What subscription do you have?

Pro 20x.

Which model were you using?

The failure started on GPT-5.6 Sol after changing reasoning effort from low to high. The affected GPT-5.6 model configuration uses Responses Lite over the Responses WebSocket.

Retries also failed with:

  • GPT-5.6 Sol, high and low effort
  • GPT-5.6 Terra, high effort

After compaction, GPT-5.5 worked, and switching back to GPT-5.6 Sol high also worked. This does not appear to be a general outage or a prompt-content rejection.

What platform is your computer?

Linux 6.17.0-35-generic x86_64.

What terminal emulator and version are you using (if applicable)?

Ghostty 1.3.1 (TERM=xterm-ghostty), no tmux/zellij.

Codex doctor report

Not applicable. The rollout and diagnostic DB contain a deterministic transition from an incremental request to a full-history request, followed by repeated top-level Responses errors.

Affected thread ID:

019f54e4-c359-7f33-9d38-be0d864eb664

What issue are you seeing?

A long Responses Lite session worked while requests could extend the cached response incrementally. Changing reasoning effort invalidated WebSocket request reuse, so Codex resent the complete history. That request returned:

■ Request blocked.

Every subsequent turn—including ping and continue, different GPT-5.6 variants, new WebSocket connections, and an Esc rollback—returned the same response. The session recovered only after compaction reduced the context substantially.

The important sequence was:

| State | Estimated context | Request behavior | Result |
|---|---:|---|---|
| Last stable turn before investigation | ~163,160 tokens | Incremental | Success |
| After fetching several prior GitHub issue bodies | ~172,528 tokens | Incremental | Success |
| Reasoning effort changed low → high | ~172,528 tokens | Full resend | Request blocked. |
| Two-turn rollback | ~163,146 tokens | Full resend | Still blocked |
| Compacted context | ~36,451 tokens | New baseline | Success |

The diagnostic log records the exact reuse transition immediately before the first failure:

incremental request failed, websocket reuse properties didn't match
unhandled responses event: error
Turn error: Request blocked.

There were 12 blocked attempts over approximately four and a half minutes. Later attempts used fresh WebSocket connections, so the failure was not confined to one poisoned connection.

This suggests that incremental Responses Lite requests can grow a session beyond a limit that applies when the complete history must be sent again. A request-property change then exposes the limit and strands the thread because subsequent requests no longer have a usable incremental anchor. The exact backend constraint may be tokens, serialized bytes, or another full-request validation guard; the client currently discards the error details needed to distinguish them.

What steps can reproduce the bug?

The precise backend threshold is not visible, but the observed reproduction is:

  1. Start a GPT-5.6 Responses Lite session using the Responses WebSocket.
  2. Grow the context to roughly 160K–173K estimated tokens while continuing to reuse previous_response_id incrementally.
  3. Complete another successful turn that adds a substantial tool result. In this case, six GitHub issue bodies added 27,985 serialized characters / 6,972 original tool-result tokens.
  4. Change reasoning effort, for example from low to high.
  5. Submit a short prompt.
  6. Observe the reuse mismatch followed by a full response.create and Request blocked.
  7. Retry with a trivial prompt, another GPT-5.6 model, or a fresh WebSocket connection. Observe the same failure.
  8. Roll back the failed turn—or even roll back the preceding successful turn—then retry. Observe that the full request can remain blocked.
  9. Compact the thread to a much smaller context and retry. Observe that inference succeeds, including after switching back to GPT-5.6.

A deterministic integration test could use a mocked Responses endpoint with different limits for incremental and full requests, then change reasoning effort after growing history past the full-request limit.

What is the expected behavior?

Changing a request property such as reasoning effort should not make an otherwise valid resumable thread permanently unusable.

If the complete request cannot be accepted after incremental reuse is invalidated, Codex should do at least one of the following:

  • compact proactively before the full resend;
  • recover automatically after the backend rejects the oversized full request;
  • retain an incremental baseline that remains usable when safe;
  • surface a specific, actionable error explaining that compaction is required.

Esc rollback should also be able to recover the thread once enough history has been removed, without requiring an unrelated model switch to trigger compaction.

Additional information

The current upstream reuse check explicitly compares reasoning settings:

https://github.com/openai/codex/blob/9e552e9d15ba52bed7077d5357f3e18e330f8f38/codex-rs/core/src/client.rs#L306-L355

When those properties differ, get_incremental_items() returns None:

https://github.com/openai/codex/blob/9e552e9d15ba52bed7077d5357f3e18e330f8f38/codex-rs/core/src/client.rs#L1164-L1178

prepare_websocket_request() then falls back to a full ResponseCreate without previous_response_id:

https://github.com/openai/codex/blob/9e552e9d15ba52bed7077d5357f3e18e330f8f38/codex-rs/core/src/client.rs#L1222-L1238

There is also a separate diagnostic problem. The WebSocket wrapper parses the backend error code and message, but generic mapping requires a status code:

https://github.com/openai/codex/blob/9e552e9d15ba52bed7077d5357f3e18e330f8f38/codex-rs/codex-api/src/endpoint/responses_websocket.rs#L580-L635

For this failure, the top-level event had no mappable status, so it fell through to the generic stream parser. That path logs only the event kind:

https://github.com/openai/codex/blob/9e552e9d15ba52bed7077d5357f3e18e330f8f38/codex-rs/codex-api/src/sse/responses.rs#L466-L468

As a result, the raw backend code/message that could identify the actual constraint is lost, leaving only Request blocked. in the transcript and logs.

Suggested implementation direction:

  1. Preserve and log/surface the structured top-level WebSocket error even when it has no HTTP status.
  2. Before falling back from an incremental request to a complete-history response.create, compare the request against the supported full-request budget and compact when necessary.
  3. Add recovery coverage for a reuse-property change after a long incremental session, including rollback and retry behavior.

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗