Skip to content

prompt_async endpoint returns 524 timeout behind Cloudflare due to unnecessary stream() wrapper #16180

Closed as not planned

Description

@InstaxAI

Description

The prompt_async endpoint (POST /:sessionID/prompt_async) wraps a fire-and-forget SessionPrompt.prompt() call in Hono's stream() helper. This opens a streaming HTTP response that never writes any data before closing. Behind reverse proxies with first-byte timeouts (Cloudflare's non-configurable 100s timeout on Free/Pro plans), this causes 524 A Timeout Occurred errors — even though the prompt was successfully accepted server-side.

The frontend then shows "Send failed" and reverts the input text, but the message was already processed. This creates a confusing UX where messages appear to fail but actually succeed.

Steps to reproduce

  1. Deploy OpenCode web behind Cloudflare CDN (Free or Pro plan)
  2. Send a message via the web UI
  3. If the streaming response doesn't complete fast enough, Cloudflare returns 524
  4. Frontend shows "Send failed" toast and reverts input to the text box
  5. But the message was actually received and processed by the server

Cloudflare tunnel error log (production)

ERR error="stream canceled by remote with error code 0" connIndex=2
ERR Request failed error="Incoming request ended abruptly: context canceled"
    dest=https://example.com/session/ses_.../command

Root cause

In packages/opencode/src/server/routes/session.ts, the prompt_async handler:

async (c) => {
  c.status(204)
  c.header("Content-Type", "application/json")
  return stream(c, async () => {
    const sessionID = c.req.valid("param").sessionID
    const body = c.req.valid("json")
    SessionPrompt.prompt({ ...body, sessionID })  // fire-and-forget, no await, no stream.write()
  })
},

The stream() wrapper opens a chunked transfer-encoding response but the callback never calls stream.write() — it just fires off the prompt and exits. This creates an empty streaming response that reverse proxies interpret as a stalled connection.

Expected behavior

prompt_async should return a direct 204 No Content response immediately, since it's designed to be fire-and-forget. An atomic HTTP response completes in milliseconds and is not susceptible to proxy timeout issues.

OpenCode version

1.2.17

Operating System

Ubuntu 24.04 (server behind Cloudflare Tunnel)

Activity

  1. added
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    on Mar 5, 2026
  2. assigned and unassigned on Apr 26, 2026
  3. removed
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    on May 3, 2026
  4. cogni-ai-ee commented on May 13, 2026

    @cogni-ai-ee

    I think I hit the same problem.
    Agent last command:

    |  Shell    {"command":"printf \"%s\\n\" \"$PATH\"","description":"Check PATH environment variable"}
    
    [13:32:46.959] INFO (#181): loop {
      service: "session.prompt",
      "session.id": "ses_1de78b8a7ffedED7rxQh4nklxa",
      step: 9,
    }
    Error: The operation was canceled.
    

    before stuck in 2h hung.

    The following log can be found in ~/.local/share/opencode/log/*:

    ERROR 2026-05-13T13:32:10 +97347ms service=llm providerID=opencode modelID=gemini-3-flash session.id=ses_1de78b8a7ffedED7rxQh4nklxa small=false agent=build mode=primary error={"error":{"name":"AI_APICallError","url":"https://opencode.ai/zen/v1/models/gemini-3-flash:streamGenerateContent?alt=sse","requestBodyValues":{"generationConfig":{"maxOutputTokens":32000,"temperature":1,"topK":64,"topP":0.95,"thinkingConfig":{"includeThoughts":true,"thinkingLevel":"high"}},"contents":[{"role":"user","parts":[{"text":"You are operating as the default agent. ...
    "statusCode":524,"responseHeaders":{"cache-control":"private, max-age=0, no-store, no-cache, must-revalidate, post-check=0, pre-check=0","cf-ray":"9fb203fc2cb4f56e-SJC","connection":"keep-alive","content-type":"text/html; charset=UTF-8","date":"Wed, 13 May 2026 13:32:09 GMT","server":"cloudflare","transfer-encoding":"chunked"},"responseBody":"... Your browser reached Cloudflare successfully. Cloudflare was working normally. The upstream host, aiplatform.googleapis.com, did not respond in time. Cloudflare returned Error 524: A timeout occurred. Timestamp: 2026-05-13 13:32:09 UTC Cloudflare location: San Jose Cloudflare Ray ID: 9fb204046eaff56e The error is marked retryable.

    AI suggestion fix:

    The fix should be: stop treating prompt_async as a streaming response and return an immediate non-streaming 204 No Content after scheduling the prompt work in the background.
    Why: The issue describes a handler that wraps a fire-and-forget call in a streaming response. That creates an HTTP connection that may stay open without sending a first byte. Cloudflare interprets that as a stalled origin response and returns 524. Since prompt_async is semantically “accepted, process later,” the correct response is an immediate atomic 204.
    Replace the empty streaming response with an immediate plain 204 response after backgrounding the prompt work. That aligns the implementation with the endpoint contract and prevents Cloudflare 524s.

  5. cogni-ai-ee commented on May 13, 2026

    @cogni-ai-ee

    Potential fix in GH-16181 which was closed, please re-open.
    Problem happens on daily basis, 1/10 sessions become stuck for very long time.

  6. github-actions commented on Jul 19, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

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