Bedrock Mantle openai.gpt-5.5: response.failed with server_error on successfully streamed turns triggers 5× retry loop

Resolved 💬 0 comments Opened Jun 9, 2026 by steven-terrana Closed Jun 10, 2026

What version of Codex CLI is running?

codex-cli 0.137.0 (also reproducible on the Codex Desktop App build shipped today)

What subscription do you have?

Amazon Bedrock

Which model were you using?

openai.gpt-5.5 via bedrock-mantle.us-east-2.api.aws

What platform is your computer?

Darwin 24.6.0 arm64 arm

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

Ghostty 1.3.1

Codex doctor report

{
  "schemaVersion": 1,
  "overallStatus": "ok",
  "codexVersion": "0.137.0",
  "checks": {
    "auth.credentials": {
      "status": "ok",
      "summary": "OpenAI auth is not required for the active model provider",
      "details": {
        "model provider requires OpenAI auth": "false"
      }
    },
    "config.load": {
      "status": "ok",
      "summary": "config loaded",
      "details": {
        "model provider": "amazon-bedrock",
        "model": "openai.gpt-5.5"
      }
    }
  }
}

(Auth uses credential_processaws-vault export --format=json → AWS SDK SigV4. Verified working — no 401s, signatures valid, region resolved to us-east-2 via [model_providers.amazon-bedrock.aws].)

What issue are you seeing?

Every turn against openai.gpt-5.5 on Bedrock Mantle ends in the 5-retry "Reconnecting…" loop and then stream disconnected before completion: The server had an error while processing your request. Sorry about that!. This happens on the very first message of a brand-new conversation, with prompts as short as hi — no tool call required.

The model does generate a full response on every retry. The user-visible UI stacks five fresh replies between the "Reconnecting" lines, e.g.:

> hi
Hi. What can I help with in this repo?
Reconnecting 1/5
Hi. What would you like to work on?
Reconnecting 2/5
Hi. What would you like to work on?
Reconnecting 3/5
Hi. What would you like to work on?
Reconnecting 4/5
Hello. What would you like to work on?
Reconnecting 5/5
Worked for 26s
Hi. What would you like to work on?
stream disconnected before completion: The server had an error while processing your request. Sorry about that!

Each "Reconnecting" attempt is a brand-new Bedrock response (distinct resp_… IDs), and each one is generated to completion. Bedrock is being charged for five turns; the user sees zero successful turns.

Root cause from on-disk SQLite trace logs

Pulled from ~/.codex/logs_2.sqlite (target='codex_api::sse::responses'). Bedrock streams the reply normally:

"type":"response.created"
"type":"response.in_progress"          <-- (logged by Codex as "unhandled responses event")
"type":"response.output_item.added"
"type":"response.content_part.added"   <-- (unhandled)
"type":"response.output_text.delta"    delta="Hi"
"type":"response.output_text.delta"    delta="."
"type":"response.output_text.delta"    delta=" What"
... ~12 more deltas, full reply assembled successfully ...
"type":"response.output_text.done"     <-- (unhandled)
"type":"response.content_part.done"    <-- (unhandled)
"type":"response.output_item.done"     item.status=completed, full text present

Then, instead of response.completed, Bedrock sends response.failed with the same response object plus an error field:

{
  "type": "response.failed",
  "sequence_number": 18,
  "response": {
    "id": "resp_4qlg63ro4mq4oyt7q6zdaqlkwmujh34opru2dwfkdcmimdsmrzxq",
    "created_at": 1781009164,
    "completed_at": 1781009165,
    "error": {
      "code": "server_error",
      "message": "The server had an error while processing your request. Sorry about that!"
    },
    "model": "openai.gpt-5.5",
    "output": [ { "type": "message", "status": "completed", "content": [ { "type": "output_text", "text": "Hi. What can I help with in this repo?" } ] } ],
    "usage": null,
    ...
  }
}

Codex's response.failed handler in codex-rs/codex-api/src/sse/responses.rs does not match server_error against any of its specific categories (is_context_window_error, is_quota_exceeded_error, is_usage_not_included, is_cyber_policy_error, is_invalid_prompt_error, is_server_overloaded_error), so it falls through to the generic branch and is classified as ApiError::Retryable:

} else {
    let delay = try_parse_retry_after(&error);
    let message = error.message.unwrap_or_default();
    response_error = ApiError::Retryable { message, delay };
}

This kicks off the responses_retry loop. Five fresh Bedrock turns later, the same server_error arrives every time and the request is finally surfaced as stream disconnected before completion.

Two issues at play
  1. Bedrock side: bedrock-mantle.us-east-2 is sending response.failed with error.code = "server_error" for openai.gpt-5.5 requests whose content streamed to completion (output items present, status completed, full text in the message). Either the content is correct and the failure flag is spurious, or the failure is real and the streamed output should have been suppressed — but not both.
  1. Codex side: When response.failed arrives after response.output_item.done with a completed status and non-empty content, retrying produces five identical-looking but distinct charged responses with the same outcome. A Retryable classification for server_error is too aggressive given how Bedrock-mantle is actually using response.failed today; it would be safer to either (a) treat response.failed as terminal when the response object already contains a completed output item, or (b) downgrade generic server_error to non-retryable for the amazon-bedrock provider until the Bedrock-side behavior is corrected.
Distinct response IDs across the 5 retries (single user prompt)
resp_4ozbix2pqtlr23b2qjygf2zglfyqzda4wc7ks4glwrouyifw3tvq
resp_l3hlc7wlhfz5v6xb3cxl2smpio2hhg7vvlxlghob5w7enXXXXXX
resp_vy35pwwwshu4n6clrgrt4f4guyuxnfgi454otjomwolklXXXXXX
resp_63wl44uhsxmv6a3fznbjpq5mb627lrmgprac3axk2rf2vXXXXXX
resp_qefhafuy75h2rrnzkbhvegqgmbxolh3nrqvo4jz35oyt5h2lugra
resp_4qlg63ro4mq4oyt7q6zdaqlkwmujh34opru2dwfkdcmimdsmrzxq

(Last 6 chars of three IDs masked; remaining IDs match the live trace verbatim.)

What steps can reproduce the bug?

  1. Configure Codex against Bedrock Mantle in ~/.codex/config.toml:

```toml
model = "openai.gpt-5.5"
model_provider = "amazon-bedrock"
model_reasoning_effort = "medium"

[model_providers.amazon-bedrock.aws]
region = "us-east-2"
```

  1. Auth via either AWS_BEARER_TOKEN_BEDROCK or credential_process in an AWS profile (both reproduce; auth itself is fine — no 401s, signatures valid).
  2. From any working directory (in or out of a git repo, with --skip-git-repo-check, sandbox read-only or workspace-write, with or without MCP servers, plugins all disabled), send any short prompt:

``bash
codex exec --skip-git-repo-check --model openai.gpt-5.5 "hi"
``

  1. Observe 5× stream disconnected - retrying sampling request (n/5 in <ms>ms)... warnings from codex_core::responses_retry, followed by Turn error: stream disconnected before completion: The server had an error while processing your request. Sorry about that! from codex_core::session::turn.

Reproducible 100% of the time on this account/region, on every fresh conversation. Same behavior on the Codex Desktop App.

What is the expected behavior?

Either:

  • The model's completed response is delivered to the client (Bedrock should not flag a successfully streamed turn as response.failed), or
  • The failure is treated as terminal so the user is not silently charged for five duplicated retries, and the failure is surfaced quickly with a clear message.

Additional information

  • Auth path: credential_process = aws-vault export --format=json <profile> → AWS SDK SigV4. No AWS_BEARER_TOKEN_BEDROCK set; AWS region resolved from the provider config.
  • The four "unhandled responses event" lines for response.in_progress, response.content_part.added, response.content_part.done, response.output_text.done appear consistently but are not load-bearing here — text content arrives via the handled response.output_text.delta events. Mentioning them only because they're highly visible in the trace.
  • Pi/SDK clients hitting the same Bedrock endpoint with simpler tool sets do not trigger this; they don't subscribe to the response.failed event in the same way and tolerate the embedded error field on otherwise-successful streams.
  • Closely related but not the same as #26860 (silent halt with output_tokens=0) and #19122 (image_generation_call retry loop). The pattern here is "model produces a full reply, Bedrock tags it failed, Codex retries 5×".

View original on GitHub ↗