Skip to content

Intermittent OpenAI Service Unavailable: upstream connection failure across models and sessions #52269

Closed as not planned

Description

@pedrommone

Summary

OpenCode intermittently fails on the OpenAI provider with:

Service Unavailable: upstream connect error or disconnect/reset before headers. reset reason: remote connection failure

Some requests succeed, while others repeatedly fail and display automatic retries. Rebooting the computer and reconnecting OpenAI authentication did not resolve the problem.

Environment

  • OpenCode: 1.18.33 (verified with opencode --version)
  • OS: Linux
  • Provider: openai
  • Affected model IDs observed in logs: gpt-5.6-sol, gpt-6-sol, gpt-6.1-sol
  • Runtime reported in logs: ai-sdk

Observed behavior and evidence

  • Failures occurred across multiple conversations on 2026-09-30, rather than only one session.
  • Logs repeatedly report AI_APICallError: Service Unavailable.
  • In one affected conversation, OpenCode read three PNG screenshots, then the next gpt-6.1-sol request failed at 09:40:49 UTC.
  • Subsequent retries sometimes failed in under one second.
  • Other conversations continued executing tools around the same period, consistent with intermittent rather than universal failure.
  • Two distinct run IDs were issuing requests for the same affected session around 09:41–09:43 UTC. This is an observation only; its relevance to the failure is unknown.

Sanitized excerpt:

2026-09-30T09:40:40.581Z stream providerID=openai modelID=gpt-6.1-sol
2026-09-30T09:40:40.586Z llm.runtime=ai-sdk llm.provider=openai llm.model=gpt-6.1-sol
2026-09-30T09:40:49.367Z stream error: AI_APICallError: Service Unavailable
2026-09-30T09:40:51.395Z stream providerID=openai modelID=gpt-6.1-sol
2026-09-30T09:40:51.825Z stream error: AI_APICallError: Service Unavailable
2026-09-30T09:40:56.236Z stream providerID=openai modelID=gpt-6.1-sol
2026-09-30T09:40:56.389Z stream error: AI_APICallError: Service Unavailable

Reproduction

  1. Use an OpenAI model in OpenCode for a coding conversation with tool use.
  2. Continue working normally.
  3. Intermittently, a request fails with the error above and automatic retries also fail.

The failure is not reliably reproducible on demand. Reading images preceded one failure, but failures in other conversations mean images are not established as the cause.

Expected behavior

Requests complete normally, or transient failures recover with actionable diagnostics identifying the failed endpoint, HTTP status, and provider request ID when available.

Troubleshooting already attempted

  • Rebooted the computer.
  • Reconnected OpenAI authentication.
  • Retried/continued the conversation.
  • Inspected local logs and confirmed failures across models and conversations.

A controlled MCP-enabled versus MCP-disabled comparison has not yet been performed. The root cause is not established; this report does not assume a provider outage, tool-count problem, or overlapping-run problem.

Related reports

Is this a known OpenAI integration or retry/recovery issue in 1.18.33? What additional sanitized diagnostics would help distinguish a gateway connection failure from a request-specific problem?

Activity

  1. github-actions commented on Sep 30, 2026

    @github-actions
    Contributor

    This issue might be related to existing issues. Please check:

    • #9377: reports similar “upstream connect error or disconnect/reset before headers” wording, although with a different provider context.
    • #23944: reports frequent intermittent errors using OpenAI, with a different server-error payload.
    • #23956: reports intermittent OpenAI errors in OpenCode CLI, also with a different payload.
  2. pedrommone commented on Sep 30, 2026

    @pedrommone
    Author

    Additional diagnostic detail: persistent per-conversation failure

    Once an affected conversation enters the failing state, normal retries/continue do not restore it. The user reports that switching models or compacting the conversation allows it to recover.

    This distinguishes the observed behavior from a transient failure that clears on the next unchanged request. Compaction changes the conversation context, and switching models changes the model/request route, so conversation/request-dependent behavior should be investigated alongside upstream connectivity.

    This is user-reported recovery behavior, not yet a controlled reproduction. It does not establish context size, malformed history, tool inventory, or a particular provider route as the root cause.

  3. pedrommone commented on Sep 30, 2026

    @pedrommone
    Author

    Recovery clarification: original Sol model works after compaction

    The user confirmed this sequence:

    1. A Sol conversation enters a persistent Service Unavailable failure state.
    2. Restarting OpenCode does not recover the conversation.
    3. Compaction runs using Luna and succeeds.
    4. The conversation returns to the original Sol model and works again.

    This is user-reported behavior, not an independently controlled reproduction. It strengthens the history/context-dependent hypothesis: the original model can work after the history is compacted, while restarting with the existing history does not help. It does not prove a prompt-cache bug, context-limit violation, malformed tool history, or any specific root cause. Compaction also changes the request structure and may affect provider-side state.

  4. pedrommone commented on Sep 30, 2026

    @pedrommone
    Author

    Log-verified recurrence after image tool results

    Inspected the local logs for two compaction/recovery/failure cycles in the same affected conversation on 2026-09-30. All timestamps below are UTC.

    Time Observed event
    10:01:36 gpt-6-luna compaction begins.
    10:02:31 onward gpt-6.1-sol resumes and executes tools.
    10:02:52 Reads a 375px-wide PNG screenshot, resized to 299x2000.
    10:03:15–16 Reads additional PNG screenshots; a 768px-wide image is resized to 721x2000.
    10:03:18 Next Sol request fails with AI_APICallError: Service Unavailable; subsequent retries fail.
    10:05:15–10:06:32 A new run resumes the same conversation; Sol requests still fail.
    10:07:13 gpt-6-luna compaction begins again.
    10:07:30 onward gpt-6.1-sol resumes and executes several tool steps.
    10:08:11 Reads the 375px-wide screenshot, resized to 299x2000.
    10:08:21–22 Reads the 768px-wide screenshot, resized to 721x2000.
    10:08:25 Next Sol request fails with Service Unavailable; retries fail through 10:09:44.

    The initial 09:40 failure also immediately followed PNG tool reads.

    This narrows the investigation to a recurring association with image-bearing history/tool results. Compaction is temporary recovery, not a lasting fix: the agent can reread the screenshots and reenter the failing state.

    Image payload size, multi-image handling, tool-result image serialization, and provider processing are hypotheses only. These logs do not expose the outbound payload, HTTP response headers, or request IDs, so they do not establish a root cause or a cache defect. No private paths, session contents, or image attachments are included here.

  5. matheustavarestrindade commented on Oct 1, 2026

    @matheustavarestrindade

    I've been having the same problem.

  6. SuKuShaing commented on Oct 2, 2026

    @SuKuShaing

    The same thing happens to me on Windows.

  7. mynameistito commented on Oct 5, 2026

    @mynameistito
    Contributor

    Additional report

    Another report shows a similar user-facing sequence while using openai/gpt-6-luna: OpenCode displays Retrying in 8s · attempt 7 · The backend is temporarily overloaded. Please retry. After the retries, the model was no longer available in /models and the session used Muse Spark 1.3 Free instead.

    This may be an interaction between the overload/retry path and model-catalog or fallback handling. Could you check whether repeated provider errors refresh or mutate the effective model/provider? A transient failure should not silently change the selected model or route the session to a different provider.

  8. NachoVazquez commented on Oct 6, 2026

    @NachoVazquez

    We hit the same failure in a different client (Pi) and I think this answers the diagnostic question in the report.

    The variable is request size, not the prompt and not the images themselves.

    Method: take a normal request body and prepend whitespace inside the JSON document. JSON parsers ignore leading whitespace, so the semantic payload is identical. Only the transmitted size changes.

    Result on the OpenAI provider (api.openai.com/v1/responses, OAuth, gpt-6.1-sol):

    Body size Result
    1,048,575 bytes HTTP 200
    1,048,577 bytes HTTP 503, upstream connect error or disconnect/reset before headers. reset reason: remote connection failure

    We did not test the single byte in between. The failing request repeats the same body, which matches the persistence you describe: restarting or retrying does not help, because the client resends the same oversized history. Compaction removes content and recovers the session, which matches your log.

    Lossless compression of the unchanged request also recovers it. The same 1.61 MB request, with both PNG tool results still in history, succeeded at 993,986 bytes with Content-Encoding: zstd, and at about 862 KB with gzip. Nothing was dropped from the conversation.

    Two caveats. Our measurements come from Pi, not OpenCode, and our client used a WebSocket transport for one provider. OpenCode's transport may differ, so the WebSocket detail may not transfer. The size dependence should.

    OpenAI also documents zstd request compression for /v1/responses with 128 MiB limits, so this boundary is not a documented API limit. We have not identified which component enforces it.

  9. bernardokcosta commented on Oct 7, 2026

    @bernardokcosta

    I've been having the same problem.

  10. JorgeLucasTC commented on Oct 7, 2026

    @JorgeLucasTC

    I'm having the same problem

  11. pedrommone commented on Oct 8, 2026

    @pedrommone
    Author

    Thanks @NachoVazquez, that matches everything in my logs. The sticky failure, the image reads right before it, and recovery after compaction all fit a request body crossing ~1 MiB (1,048,576 bytes). Retrying or restarting can't help because the client resends the same oversized history.

    Summary so far

    • 1,048,575 bytes → HTTP 200; 1,048,577 bytes → HTTP 503 upstream connect error or disconnect/reset before headers
    • Same request compressed with zstd/gzip succeeds with no history removed
    • Reproduces outside OpenCode (Pi, and the Codex extension against chatgpt.com/backend-api/codex/responses), so the limit is on OpenAI's side, not documented, and much lower than the published limits

    Ask for maintainers (@rekram1-node)

    Since OpenCode can't change OpenAI's gateway, could we get a client-side mitigation?

    1. Send request bodies compressed (Content-Encoding: zstd, which OpenAI documents for /v1/responses), at least for the OpenAI provider
    2. Or detect bodies near 1 MiB and auto-compact / downscale or drop old image tool results before sending
    3. At minimum, show a clear error ("request too large for provider") instead of looping retries on a 503 that will never succeed

    Ask for everyone affected (@JorgeLucasTC @bernardokcosta @NachoVazquez @SuKuShaing @matheustavarestrindade)

    Please open a ticket with OpenAI support (help.openai.com or support@openai.com) and link this issue, including the byte-size repro above. My case (16436407 / 16697544) is stuck with the AI agent and hasn't reached a human yet. More reports with the same evidence should help get it to engineering.

    Workaround for now: compact the session (or avoid reading large screenshots) whenever it starts failing.

  12. bernardokcosta commented on Oct 10, 2026

    @bernardokcosta

    I have an open ticket with Openia (16755317), but I’ve noticed that the error consistently occurs when the context window is around 59% full. However, if I switch to a model from a provider other than Openia, compress the session, and then switch back to Openia models, it works normally; I tested the compression using Muse 1.3 Free, which is available on OpenCode.

  13. jeremyakers commented on Oct 10, 2026

    @jeremyakers

    Reposting my findings and fix here:

    I think I've found the cause, at least for the reset reason: remote connection failure variant: OpenAI's edge now rejects uncompressed request bodies larger than ~1 MiB sent to chatgpt.com/backend-api/codex/responses, regardless of token count. The official Codex CLI is unaffected because it zstd-compresses these requests by default. OpenCode sends them uncompressed.

    Reproduction (ChatGPT OAuth, sent directly to the Codex endpoint outside OpenCode):

    Request Bytes sent Result
    Small JSON request 298 B 200 OK
    Same request with ~1.5 MB of filler 1.51 MB 503 upstream connect error or disconnect/reset before headers. reset reason: remote connection failure
    Identical body with Content-Encoding: zstd 370 B 200 OK

    Testing inside OpenCode with fresh sessions, ~898 KB of message content succeeds and ~933 KB fails on all 5 retries. That's consistent with a ~1 MiB limit on the total request.

    It depends on bytes, not tokens: a mostly-whitespace 1.5 MB prompt containing ~75k tokens fails, while a real 220k-token session succeeds. In practice, sessions above roughly 220–230k tokens fail every turn, while new or small sessions and subagents work. That matches "after some requests" in this report. For me it started around 01:00 UTC on Oct 10; the same sessions had been working at 550k–890k tokens just before.

    Why Codex CLI still works: codex-rs zstd-compresses ChatGPT-backend Responses requests by default (enable_request_compression, stable, enabled by default; see responses_request_compression() in codex-rs/core/src/client.rs and codex-rs/http-client/src/request.rs). OpenCode's OpenAI OAuth fetch wrapper forwards the JSON body uncompressed.

    Suggested fix: in the OpenAI OAuth/Codex fetch path, zstd-compress the request body, set Content-Encoding: zstd, and remove any stale Content-Length, matching codex-rs. Bun provides Bun.zstdCompressSync.

    Workaround until then: add this plugin as ~/.config/opencode/plugins/codex-request-compression.ts, then restart OpenCode:

    import type { Plugin } from "@opencode-ai/plugin"
    
    const CODEX = "https://chatgpt.com/backend-api/codex/responses"
    const installed = Symbol.for("codex-request-compression")
    
    export const CodexRequestCompression: Plugin = async () => {
      const g = globalThis as typeof globalThis & { [installed]?: true }
      if (!g[installed]) {
        const base = globalThis.fetch
        globalThis.fetch = Object.assign(async (input: string | URL | Request, init?: RequestInit) => {
          if (input instanceof Request || init?.method?.toUpperCase() !== "POST" || typeof init.body !== "string") return base(input, init)
          const url = new URL(input)
          const headers = new Headers(init.headers)
          if (url.origin + url.pathname !== CODEX || headers.has("content-encoding")) return base(input, init)
          headers.set("content-encoding", "zstd")
          headers.delete("content-length")
          return base(input, { ...init, headers, body: new Uint8Array(Bun.zstdCompressSync(init.body, { level: 3 })) })
        }, { preconnect: base.preconnect })
        g[installed] = true
      }
      return {}
    }

    With this plugin, the request that previously returned 503 succeeds. The connection timeout variant in the original report may be a separate or transient edge problem, but large sessions hit this one deterministically.

  14. rmroc451 commented on Oct 11, 2026

    @rmroc451

    18. Reposting my findings and fix here:
    I think I've found the cause, at least for the reset reason: remote connection failure variant: OpenAI's edge now rejects uncompressed request bodies larger than ~1 MiB sent to chatgpt.com/backend-api/codex/responses, regardless of token count. The official Codex CLI is unaffected because it zstd-compresses these requests by default. OpenCode sends them uncompressed.
    Reproduction (ChatGPT OAuth, sent directly to the Codex endpoint outside OpenCode):

     Request
     Bytes sent
     Result
     
     
     
     
     Small JSON request
     298 B
     200 OK
     
     
     Same request with ~1.5 MB of filler
     1.51 MB
     503 `upstream connect error or disconnect/reset before headers. reset reason: remote connection failure`
     
     
     Identical body with `Content-Encoding: zstd`
     370 B
     200 OK
     
     
     
     Testing inside OpenCode with fresh sessions, ~898 KB of message content succeeds and ~933 KB fails on all 5 retries. That's consistent with a ~1 MiB limit on the total request.
     It depends on bytes, not tokens: a mostly-whitespace 1.5 MB prompt containing ~75k tokens fails, while a real 220k-token session succeeds. In practice, sessions above roughly 220–230k tokens fail every turn, while new or small sessions and subagents work. That matches "after some requests" in this report. For me it started around 01:00 UTC on Oct 10; the same sessions had been working at 550k–890k tokens just before.
     **Why Codex CLI still works:** `codex-rs` zstd-compresses ChatGPT-backend Responses requests by default (`enable_request_compression`, stable, enabled by default; see `responses_request_compression()` in `codex-rs/core/src/client.rs` and `codex-rs/http-client/src/request.rs`). OpenCode's OpenAI OAuth fetch wrapper forwards the JSON body uncompressed.
     **Suggested fix:** in the OpenAI OAuth/Codex fetch path, zstd-compress the request body, set `Content-Encoding: zstd`, and remove any stale `Content-Length`, matching `codex-rs`. Bun provides `Bun.zstdCompressSync`.
     **Workaround until then:** add this plugin as `~/.config/opencode/plugins/codex-request-compression.ts`, then restart OpenCode:
     import type { Plugin } from "@opencode-ai/plugin"
     
     const CODEX = "https://chatgpt.com/backend-api/codex/responses"
     const installed = Symbol.for("codex-request-compression")
     
     export const CodexRequestCompression: Plugin = async () => {
       const g = globalThis as typeof globalThis & { [installed]?: true }
       if (!g[installed]) {
         const base = globalThis.fetch
         globalThis.fetch = Object.assign(async (input: string | URL | Request, init?: RequestInit) => {
           if (input instanceof Request || init?.method?.toUpperCase() !== "POST" || typeof init.body !== "string") return base(input, init)
           const url = new URL(input)
           const headers = new Headers(init.headers)
           if (url.origin + url.pathname !== CODEX || headers.has("content-encoding")) return base(input, init)
           headers.set("content-encoding", "zstd")
           headers.delete("content-length")
           return base(input, { ...init, headers, body: new Uint8Array(Bun.zstdCompressSync(init.body, { level: 3 })) })
         }, { preconnect: base.preconnect })
         g[installed] = true
       }
       return {}
     }
         
           
         
     
           
         
     
         
       
     With this plugin, the request that previously returned 503 succeeds. The `connection timeout` variant in the original report may be a separate or transient edge problem, but large sessions hit this one deterministically.
    

    legend @jeremyakers, this is working for me this morning.

  15. thdxr commented on Oct 11, 2026

    @thdxr
    Member

    Thanks for the report! OpenCode 2.0 is now out and development is focused on V2, so we're closing issues filed against OpenCode 1. Please upgrade (opencode upgrade --major, details: https://anoma.ly/notes/opencode-2-0), and if this is still relevant on 2.0, reopen this issue or open a new one with your 2.0 version.

    — from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

  16. esafak commented on Oct 11, 2026

    @esafak
    Contributor

    I'm on V2 desktop and it's present

  17. bernardokcosta commented on Oct 11, 2026

    @bernardokcosta

    24. I'm on V2 desktop and it's present

    me too

  18. jeremyakers commented on Oct 12, 2026

    @jeremyakers

    Follow-up with additional reproduction and a tested workaround. I also need to correct two points in my earlier comment: the observed size limit applies to the HTTP body as transmitted, including after compression, and compression alone does not fully explain why the official Codex client avoids this.

    Compression helps, but is not sufficient

    The zstd plugin I posted fixed the compressible-text case. However, long or screenshot-heavy conversations can still exceed the observed limit after compression. Images and encrypted reasoning content are much less compressible than ordinary text.

    Direct tests against https://chatgpt.com/backend-api/codex/responses, using ChatGPT OAuth:

    Zstd-compressed HTTP body Result
    938,316 bytes (~0.89 MiB) HTTP 400 identifying an intentionally unsupported probe field: the request reached application validation
    1,200,788 bytes (~1.15 MiB) HTTP 503 with upstream connect error or disconnect/reset before headers. reset reason: remote connection failure

    These tests bracket the observed cutoff near 1 MiB. This is observed endpoint behaviour, not a documented universal OpenAI API limit. Retrying the unchanged oversized request does not address it, and there is no reliable token-count threshold—screenshots can produce large requests at relatively low context usage.

    Tested workaround: OpenCode's built-in WebSocket transport

    OpenCode 1.18.34 already has this behind:

    OPENCODE_EXPERIMENTAL_WEBSOCKETS=true opencode

    For a server deployment, set that environment variable on the service that actually launches OpenCode, then restart it. Setting it only in the browser or an unrelated shell will not affect an already-running server.

    I tested matched workloads in isolated OpenCode processes using gpt-6.1-sol and a synthetic PNG attachment of approximately 3.96 MiB base64:

    Transport setting Result
    WebSocket disabled The same upstream-connect 503, ultimately failing after ~98 seconds
    WebSocket enabled OK in ~8 seconds

    After enabling it on my running service, another request with a 3.96 MiB attachment returned OK in ~14 seconds. No images, reasoning items or conversation history were removed to make it succeed.

    Why Codex behaves differently

    In the current Codex Rust source, the built-in OpenAI provider enables WebSocket support. On reusable connections, the client can send previous_response_id with incremental input instead of repeatedly uploading the entire history. Compressed HTTP is a fallback.

    Source inspected: commit 6e5f665feb9b71e1500a5721036fbdb8e871f4b0:

    OpenCode 1.18.34's WebSocket implementation still sends the full request, but the tested WebSocket messages did not encounter the HTTP-body rejection.

    Caveats: this mode is marked experimental, and my end-to-end tests were on 1.18.34 with ChatGPT OAuth—not OpenCode v2 or API-key authentication. This addresses the reproducible size-dependent remote connection failure variant; it does not establish that every upstream-connect 503 has the same cause. I would recommend upstream transport regression coverage for screenshot-heavy and poorly compressible requests, not just large plain-text prompts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions