Skip to content

Instance service init has no timeout and can hang the bootstrap layer indefinitely #46166

Closed as not planned

Description

@CannonRS

Title:
Instance service init has no timeout and can hang the bootstrap layer indefinitely

Description:
packages/opencode/src/project/bootstrap.ts calls init() on each per-instance service
(lsp, share, format, vcs, snapshot, project) inside an Effect.forEach with
concurrency: "unbounded". Each init() is unbounded; the existing catchCause only
fires on rejection, not on hang; and there is no per-service log line. When a single
service hangs (broken native binding, deadlocked internal state, slow disk that
prevents the share/format services from enumerating, etc.) the bootstrap layer
silently waits, the rest of the services may also stall depending on shared
InstanceState, and there is no log line to point at the offending service.

#33905 covered the related plugin-init npm install and was fixed in the npm install
path. The instance service bootstrap itself is a separate layer and still has no
timeout.

Plugins: n/a
OpenCode version: dev (dc4449d)

Steps to reproduce:

  1. Replace one of the bootstrap services (e.g. format) with an implementation whose
    init() returns a never-resolving Effect.
  2. Open a project directory.
  3. InstanceBootstrap.run never returns. No log line identifies the hanging service.

Expected behaviour:

  • The hanging service's init is interrupted within a few seconds.
  • The bootstrap completes for the other services.
  • A logWarning is emitted that names the service so the misbehaving one is locatable.

Actual behaviour:

  • The bootstrap blocks indefinitely.
  • No log line is emitted until the process is killed.

Operating System: n/a (reproducible on any platform)
Terminal: n/a

Related / duplicate check:

Activity

  1. shrijayan commented on Sep 4, 2026

    @shrijayan

    Adding evidence from a production-ish reproduction (InsightForge per-project opencode serve containers, Docker Desktop on macOS, arm64, Ubuntu 22.04 sandbox, opencode 1.18.26 + 1.18.27 — the no-timeout bootstrap hang described here is exactly what we hit):

    Two stacked bootstrap waits observed, both in the critical path of the first POST /session:

    1. models.opencode.ai (models.dev catalog) fetch, no effective timeout. On our network the TCP connect to 172.66.173.149:443 succeeds and then goes silent for 210s+ (zero payload bytes; pcap + /proc/net/tcp sampled every 3s show ESTABLISHED snapshot 2→70). During the entire hang GET /global/health answers instantly while POST /session blocks — so the un-bounded init hides behind health checks. curl to the same URL from the same container: 200 in 0.29s, so it's specifically the bootstrap client's fetch pattern (~50 parallel TLS connections) getting hung/throttled.

    2. The plugin "background dependency install" wait (covered precisely in 1.18.21: plugin installer times out fetching public deps from registry.npmjs.org (NpmInstallFailedError: FetchError) — silent dead plugin / boot hang; headless run/serve hangs with any plugin #44684 — same NpmInstallFailedError … registry.npmjs.org/@opencode-ai%2fplugin error on 1.18.26/1.18.27). Notably the trigger is the plugin file's presence, not its imports — a zero-import plugin stalls identically; pre-seeding node_modules does not bypass the installer; OPENCODE_STRICT_CONFIG_DEPS=false has no effect in vivo.

    Measured impact on our worst-case network: fresh container → first successful session: 295s before mitigations, ~152s after (blocking the catalog host via docker run --add-host models.opencode.ai:127.0.0.1 removes the dominant hang loss-free — we never use the free catalog). With --pure (no plugins) boot-to-session is ~2s — consistent with the plugin path being the residual blocker.

    This matches the OP's structural point exactly: catchCause only fires on rejection, not hang; and unlike this issue's synthetic never-resolving init(), our hang is a real service (the npm installer / models fetch) whose Effect lacks a timeout. The two upstream fixes we'd need:

    Full reproduction + pcap + probe scripts: #47279 (consolidated report; happy to move everything here if maintainers prefer).

  2. CannonRS commented on Sep 4, 2026

    @CannonRS
    Author

    Thanks for the production data — this is the missing evidence for the structural point.

    #46167 (open, no review yet) implements exactly the first of your two requested fixes:
    a per-service Effect.timeout around each service.init() in InstanceBootstrap.run,
    with a logWarning naming the service that timed out. The concurrency shape stays
    unbounded; the other services still complete. That turns your "no log line until the
    process is killed" into a named warning within seconds.

    It does not address your second point — the models.dev fetch and the plugin dep-install
    being in the blocking path (#41360, #44684). Those need to become non-blocking with a
    fallback, which is a separate contract.

    One observation from our own profiling that may be relevant to the second point: even
    when the catalog fetch succeeds and the cached models.json is used, GET /provider
    stays expensive. ProviderHttpApi.list caches nothing and rebuilds the whole catalog per
    request — 213 providers, ~7500 models, a 5.8 MB response, of which toPublicInfo spends
    ~143 ms per call running Schema.is over every model (all of them pass; the data comes
    from our own catalog). On our desktop start the client requested that up to 27 times,
    so ~156 MB of JSON per start with two providers actually connected. Different layer from
    this issue, so we will file it separately rather than widen the scope here.

  3. Tarquinen commented on Oct 20, 2026

    @Tarquinen
    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 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

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