Skip to content

LLM stream connect timeout fires prematurely — arm() starts before HTTP request #728

@Spongeacer

Description

@Spongeacer

Bug Description

The LLM stream connection timeout (CONNECT_STREAM_TIMEOUT_MS = 30s) fires prematurely because the timeout timer starts before the HTTP request is actually sent.

Root Cause

In packages/opencode/src/session/llm.ts, the execution order is:

Line 448: request object created → arm() called → 30s timer starts ticking
Line 520: yield* run(...)  ← async setup work begins here

The run() function (lines 78-377) performs several async operations after the timer has already started:

Step Lines Operation
1 92-100 yield* Effect.all(...) — concurrent fetch of provider, config, auth
2 120-124 yield* plugin.trigger("experimental.chat.system.transform")
3 168-186 yield* plugin.trigger("chat.params")
4 188-200 yield* plugin.trigger("chat.headers")
5 348 streamText({...})HTTP request actually starts here

If steps 1-4 take ~5 seconds, the actual time waiting for the provider's first token is only ~25 seconds instead of the intended 30 seconds.

Symptoms

  • Users report timeout errors before 30 seconds of actual waiting
  • Error message: LLM stream connection timed out after 30000ms without provider progress
  • Affects providers with higher latency (e.g., domestic China APIs like Kimi, Xiaomi Token Plan)
  • 12 occurrences found in a single user's database

Additional Issues

  1. No retry on timeout: The SessionRetry.policy in retry.ts does not recognize connection timeout errors as retryable — only API errors (5xx, rate limit) are retried.
  2. Not configurable: connectTimeoutMs parameter exists in StreamInput but is never passed from any configuration source.

Expected Behavior

The 30-second timeout should measure the time from when the HTTP request is sent to when the first provider progress event is received, not including internal setup time.

Suggested Fix

Move the arm() call to after run() returns, so the timeout only measures actual network + provider response time.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions