Skip to content

opencode serve accepts requests while plugin npm install is still blocking the event loop #27971

Closed as not planned

Description

@marcusrbrown

opencode serve accepts requests while plugin npm install is still blocking

OpenCode's HTTP server starts listening and emits server.connected on the SSE stream before plugin npm reify finishes. During the reify window the event loop is blocked, so any API call hangs and eventually fetch faileds with no useful error. We've measured this window at 5+ minutes on CI runners.

There is no way for a caller to know the server is ready to process requests.

Related: #19197 (OpenCode 1.3.2 has ~75 seconds startup delay). Same root cause, more severe in CI environments.

Repro

# Start a server with a fresh cache (no warm npm cache) and a plugin in config
rm -rf ~/.cache/opencode/packages/oh-my-openagent
opencode serve --port 4096 &

# Immediately try to make any API call
sleep 1
curl --max-time 10 -sS http://localhost:4096/session/list
# → curl: (28) Operation timed out after 10001 milliseconds with 0 bytes received

The server is bound and the SSE server.connected event has already been emitted, but /session/list never gets a response until npm reify completes.

Observed timeline (production CI)

Time Event
00:00 opencode serve spawned
00:01 Server bound, SSE emits server.connected
00:01 Client (@opencode-ai/sdk) sends POST /session
00:01 npm reify starts for @fro.bot/systematic, oh-my-openagent
04:58 npm reify completes (298s)
04:59 Server starts processing the queued /session request — too late, client already aborted with fetch failed

Sample log from a CI run: 298s blocking window

What we'd like upstream

One of:

  1. Block server bind until plugin reify completes. Simplest model — clients can rely on "if I can connect, you're ready".
  2. Emit a server.ready event on the SSE stream after reify. Lets clients distinguish "connected" (TCP bound) from "ready" (event loop free). Backwards-compatible — existing clients that connect-and-go don't break, new clients can wait for ready.
  3. /health endpoint that returns 503 during reify, 200 once ready. Most ergonomic for HTTP clients, no SSE knowledge needed.

Option 2 is the smallest semantic change. Option 3 is the most conventional. Either works for our use case.

Mitigation we've applied downstream

fro-bot/agent#492 — exponential retry backoff (5s → 15s → 30s → 60s) with ~/.cache/opencode/packages/ cached in CI. Reify still happens; the cache just makes it faster. Backoff covers the cold-cache window.

This works but is not a substitute for a real readiness signal — if reify exceeds 110s total wall clock, the client gives up.

Repro environment

  • OpenCode 1.14.41 (also reproduces on 1.14.48, 1.15.0, 1.15.1)
  • Plugins: @fro.bot/systematic, oh-my-openagent
  • Ubuntu 24.04 GitHub Actions runner (cold cache)

Happy to provide additional logs or test against a candidate fix.

Activity

  1. github-actions commented on Jul 17, 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