Responses WebSocket messages must have type response.create. does not come from OpenAI's servers in any traced report. It is written by a local Responses proxy that sits between Codex and the model. In every case traced so far, that proxy is codex-router, a third-party router that people install to use non-OpenAI models inside Codex.
Older router builds accept only one kind of WebSocket message, response.create. When you send a follow-up, answer a question card, or steer while a turn is still running, Codex sends a second message on the same connection, response.interrupt. The router answers it with HTTP 400 and the turn stops.
The router fix is PR #1004, merged on October 12, 2026. What you do next depends on how the router got onto your machine:
| What you find | What to do |
|---|---|
openai_base_url points to 127.0.0.1:4202, router installed with the one-line installer | Update the checkout, run doctor --fix, fully restart Codex |
| Router installed with Homebrew | brew upgrade still installs v0.6.0 (as of October 22, 2026), which predates the fix; use the workaround or disable the router for now |
| You need mid-turn follow-ups to stop failing today and cannot update | Try instant_interrupt = false as a temporary, untested workaround |
| No local proxy or custom base URL in your Codex config | Your case is outside this explanation; report it on openai/codex #52221 |
Why “must have type response.create” only appears mid-turn
Codex talks to the Responses API over a WebSocket: one long-lived connection on which the client sends small JSON messages (often called frames), each with a type field. A turn starts with response.create, the turn-start event documented in OpenAI's WebSocket Mode guide.
The current Codex client does one more thing. While a response is still streaming and you add input, Codex can cut that response short by sending this on the same socket (responses_websocket.rs):
{"type":"response.interrupt","response_id":"…","mode":"discard_partial_items"}It then waits for response.interrupt.accepted or response.interrupt.failed. This behavior sits behind a Codex feature flag, instant_interrupt, which is marked as under development and enabled by default (features/src/lib.rs). Follow-ups, question-card replies, and steering are exactly the inputs that trigger it.
codex-router's WebSocket bridge, up to release v0.6.0 and on main before October 12, checked every incoming message and refused anything that was not response.create (issue #1019). The refusal is the full error Codex shows:
{"type":"error","status":400,"error":{"type":"invalid_request_error","message":"Responses WebSocket messages must have type response.create."}}The first message of a turn passes. Only the extra message sent while Codex is working gets rejected. That is why the error typically appears right after new input during an active turn, whether in Codex Desktop on macOS or Windows, the CLI, or Codex Remote viewed on an iPhone (#52221). The same guard also exists in some forks of the router, so a local proxy with a different name can print the identical string.

“I only use GPT-6.1 Sol, why is a router involved?”
The router's Codex integration writes a managed block into ~/.codex/config.toml that sets openai_base_url to http://127.0.0.1:4202/_codex-router/<generated-capability>/v1 (older setups show http://127.0.0.1:4202/v1 ). See the router README. openai_base_url redirects Codex's built-in OpenAI provider, so native GPT turns also travel through the router, not only the external models you added. The reports in #52221 match this: the people who hit the error on gpt-6.1-sol and then checked their config found openai_base_url pointing at 127.0.0.1:4202.
Check whether a local router sits in Codex's path
Run these checks on the computer that runs the Codex turn. For Codex Remote, that is the Mac host, not the phone.
1. Look for a local base URL in your Codex config. On macOS or Linux:
grep -n -E 'openai_base_url|base_url|codex-router' ~/.codex/config.toml \
| sed -E 's#_codex-router/[^/"]+#_codex-router/…#'On Windows, in PowerShell:
Select-String -Path "$HOME\.codex\config.toml" -Pattern 'openai_base_url|base_url|codex-router' |
ForEach-Object { $_.Line -replace '_codex-router/[^/"]+', '_codex-router/…' }The second half of each command masks the generated path segment. That segment works as a local password for the router, so never paste the full URL into an issue, a chat, or a screenshot.
| What the output shows | What it means |
|---|---|
openai_base_url = "http://127.0.0.1:4202/…/v1" inside # BEGIN codex-router-managed | codex-router handles every turn, native GPT models included |
Another localhost or LAN address in openai_base_url or a [model_providers.*] table | A different local proxy or gateway is in the path; check whether it accepts response.interrupt |
No openai_base_url and no custom provider in use | No local proxy in the config; skip to the reporting section below |
2. Confirm that Codex sends interrupt messages. Run codex features list and find the instant_interrupt row. If it is enabled, Codex cuts in on a running response whenever you add input.
3. Check whether your router build has the fix. The error text itself tells you. A message ending in must have type response.create. means the router process that answered was built before the fix. A fixed router accepts response.interrupt, and for any other unsupported message type its text changes to Responses WebSocket messages must have type response.create or response.interrupt. with the code unsupported_websocket_event (source).
For an installer-based setup in the default macOS/Linux location, check the code on disk:
grep -c "response.create or response.interrupt" ~/.local/share/codex-router/src/responses-websocket.mjs0 means the checkout predates the fix. 1 or more means the fixed code is on disk, but a router process started before the update keeps running the old code until it restarts. For Homebrew, brew info codex-router showing 0.6.0 means you have the unfixed build.
Fix it by updating codex-router to a build with PR #1004
PR #1004, "fix: handle Codex response.interrupt on persistent WebSockets," handles the interrupt outside the generation queue. It aborts the local request, ends the response with response.incomplete and reason interrupted, and keeps the socket open for the next response.create. Two limits apply:
- It cancels the local HTTP request. It does not guarantee that a remote provider stops billing for a generation it has already started.
- The PR's validation was 56 passing WebSocket tests, without a live generation. One Windows user backported it and a real question-card reply during an active desktop turn then succeeded (October 15, 2026, in #52221). That is one successful test, not long-term proof.

Installed with the one-line installer: update the checkout to main
The recommended installer clones the router to ~/.local/share/codex-router from main, so you can pull the fix now (updates and rollback):
cd ~/.local/share/codex-router
./bin/model-router codex update
./bin/model-router codex doctor --fixupdateneeds amaincheckout with no edits to tracked files. Untracked files do not block it.--forcediscards tracked edits but keeps untracked ones.- The previous revision is kept, and
./bin/model-router codex rollbackreturns to it. Re-running the installer also updates frommain. doctor --fixbrings the generated config and the background service in line with the new code.
Then fully quit Codex (not only the window) and reopen it. Start a turn and send a follow-up while it is working. If the old message still appears, the router service is still running the old code: run ./bin/model-router codex stop, then ./bin/model-router codex start, and repeat the grep -c check above.
Installed with Homebrew: brew upgrade still gives you v0.6.0
As of October 22, 2026, the latest tagged release is v0.6.0, published September 15, 2026, before the fix (releases). The Homebrew formula downloads the v0.6.0 archive and has no option to build from main. brew upgrade codex-router therefore cannot deliver PR #1004 yet.
Until a release newer than v0.6.0 appears, pick one:
- Use the
instant_interruptworkaround below and keep the router. - Disable the router's Codex integration, then turn it back on after the next release.
- Switch to the installer-based setup, which tracks
main. Remove the Homebrew install first withcodex-router uninstallandbrew uninstall codex-router, so two copies do not manage the same Codex config.
When a newer release ships, run brew upgrade codex-router, then fully restart Codex and test a follow-up mid-turn.
Temporary workaround: set instant_interrupt = false
If you cannot update the router yet, you can turn off the Codex behavior that sends the rejected message. Add this to ~/.codex/config.toml, or add only the second line if a [features] table already exists (where config.toml lives):
[features]
instant_interrupt = falseFully restart Codex and check that codex features list now shows instant_interrupt off.
Treat this as a reversible stopgap, not a confirmed fix:
- The expected effect comes from reading Codex's source: with the flag off, Codex no longer cuts a running response short when you steer, so no
response.interruptmessage is sent. No public report confirms it yet. The person who traced the bug in #52221 noted they had not tested it. - The cost is slower steering. A follow-up or question-card reply waits until the current step finishes instead of interrupting it.
instant_interruptis an under-development flag, so a later Codex release can change or remove it.
Remove the line once your router includes PR #1004.
Bypass the router: disable or uninstall codex-router
If you added the router for a model you no longer need, take it out of Codex's path. One reporter in #52221 confirmed that the error stopped after they removed codex-router.
| Goal | Installer-based setup | Homebrew |
|---|---|---|
| Turn it off, keep everything for later | ./bin/model-router codex disable (undo with enable) | codex-router disable |
| Remove it | ./bin/model-router codex uninstall | codex-router uninstall, then brew uninstall codex-router |
disable removes only the Codex integration. uninstall removes the service and the managed Codex config but keeps the checkout, logs, backups, and stored provider credentials (common commands). You can delete the managed block from config.toml by hand, but the supported commands also handle the service.
Fully restart Codex afterward. Native GPT models then connect directly. Every external model you reached through the router disappears from the model picker until you turn it back on.
Will my Codex follow-up be lost after the 400?
Nobody has confirmed either way, so save it yourself. Reports differ:
- The turn usually ends at the error.
- In one Codex Remote case on an iPhone, the turn still showed as working, with a Continue button.
- In one Windows case, the question-card reply was acknowledged, but the assistant's answer could not be read while the executed-command cards stayed visible.
Before you retry, copy the text of your follow-up or question-card answer. After you apply one of the fixes above, continue the task and resend it.
Seeing it with no proxy in between? Report it on openai/codex #52221
As of October 22, 2026, no public report shows this exact string on a direct connection between Codex and OpenAI, and OpenAI has not replied on #52221. If your config check found no local proxy or custom provider, your case is outside the router explanation and worth reporting there with:
- Codex version (Desktop build number, or
codex --versionfor the CLI) and platform - When it happened, with time zone
- What you did right before: follow-up, question-card reply, or interrupt
- Whether
openai_base_urlor a custom model provider is set (yes or no, not the URL) - The
instant_interruptline fromcodex features list
Leave out API keys, tokens, the router's capability URL, and private chat text.
Two similar-looking problems have different causes. If Codex shows Reconnecting in a loop instead of a 400, see Codex Keeps Reconnecting? Find the Cause Without Losing Your Task. One Windows user first saw this error right after a failed context compaction. If compaction itself fails, see Codex Remote Compact Failed: Read the Suffix Before You Retry.
For gateway and proxy authors: accept response.interrupt and response.steer
A Responses gateway that whitelists only response.create breaks Codex steering, whichever model sits behind it.
- Codex's interrupt. Codex sends
{"type":"response.interrupt","response_id":"…","mode":"discard_partial_items"}while a response is in progress and expectsresponse.interrupt.acceptedorresponse.interrupt.failedback. PR #1004 is a working reference: handle it outside the generation queue, abort the upstream request, finish withresponse.incomplete(reasoninterrupted), keep the socket usable, and ignore late interrupts that arrive after completion. - The public steering event. OpenAI's mid-turn steering guide documents a different client event,
response.steer(withprevious_response_idandinput), for GPT-6 family models over WebSocket only. The server answers withresponse.steer.accepted,.pending, or.failed, and the steered response ends asresponse.incompletewith reasonsteered.response.interruptappears in Codex's source but not in the public guides. One user's guess that Codex sendsresponse.steerhere (codex-on-crack #11) does not match the current client code. Accepting both events covers both clients. - No WebSocket at all. A custom provider entry with
supports_websockets = falsekeeps Codex on HTTPS Responses. Coder's AI Gateway docs use this workaround. It does not apply when you redirect the built-in OpenAI provider withopenai_base_url, because that provider has WebSocket support turned on. Whether steering behaves the same over HTTPS is not documented.
To set up and test a custom provider, see Connect Codex to a Third-Party Model API Without Guessing the Protocol.
Codex response.create error: quick answers
Is “Responses WebSocket messages must have type response.create” an OpenAI outage? No report links it to an OpenAI outage. In every traced case, the string comes from a local router's WebSocket check, so OpenAI's status page will not explain it.
Does brew upgrade codex-router fix it?
Not as of October 22, 2026. The formula still installs v0.6.0, which predates PR #1004. Update an installer-based checkout instead, or use the workaround until a newer release ships.
Does it affect Codex Remote on iPhone? Yes, when the Mac that runs the turn routes Codex through the router. Apply the fix on the Mac. Nothing changes on the phone.
Can I keep codex-router and still steer mid-turn?
Yes, once the running router includes PR #1004. Confirm with the grep -c check, then restart the router service and Codex.



