Skip to content

session/resume fails right after initialize with "Location plugins did not finish activating" #57204

Open

Description

@BambinoSK

Description

I run OpenCode over ACP from a third-party IDE client (the AgentBridge plugin for IntelliJ). On client startup the normal flow completes the initialize handshake and then immediately sends session/resume for an existing session. Roughly one in six of these resume attempts fails with:

{"code":-32603, "message":"Internal error: Internal service failure: {\"errorName\":\"ServiceUnavailableError\"}"}

The server log shows the underlying cause:

level=ERROR message="ACP request failed" cause="ServiceUnavailableError: Location plugins did not finish activating"
    at cli.acp.session.resume

Retrying the same session/resume a few seconds later succeeds, so the session exists and is healthy; the failure is purely a startup race. I counted nine occurrences over four days, always within the first seconds after process start, and today one of six resume attempts failed this way while the other five succeeded.

Because initialize responds immediately and advertises sessionCapabilities.resume, the client has no signal to wait and no way to distinguish this from a real service failure, so the only safe fallback is a fresh session, which silently drops the conversation context.

In packages/cli/src/acp/service.ts on v2.0.32, resumeSession goes straight to getSession and ACPDirectories.activate with no wait for Location plugin activation. The catalog path already solved this in #46682 with an activation wait (POST /api/plugin/await-activation) before ACP's first catalog read; the resume path appears to lack the same barrier.

Plugins

No response

OpenCode version

v2.0.32

Steps to reproduce

  1. Start opencode acp in a project directory where Location activation takes a moment. A large home directory widens the window considerably; the global location watcher that subscribes to all of $HOME (core: global location watcher subscribes to all of $HOME — 2M+ file home dirs starve the event loop (~900% CPU, multi-GB memory), /api/model 503 #55937) makes the race quite reliable on my machine.
  2. Send initialize, and immediately after the response send session/resume with the sessionId of an existing session and the project cwd.
  3. Some attempts fail with the error above; the identical request sent a few seconds later succeeds.

Expected: session/resume should wait for Location plugin activation before its first directory-scoped read, the same way the catalog path does after #46682, so a resume arriving right after initialize either blocks briefly and succeeds, or returns an error a client can distinguish and retry.

Screenshot

No response

Operating System

Windows 11

Terminal

Not applicable, running over ACP from the AgentBridge plugin in IntelliJ

Activity

  1. opencode-agent commented on Oct 19, 2026

    @opencode-agent
    Contributor

    Thanks for the detailed report. I can reproduce this on v2.0.32, and it still happens on the latest dev (6bac3b9).

    To stand in for slow Location activation, I used a test project with a local plugin whose setup sleeps 15 seconds. Then I started opencode acp, sent initialize, and sent session/resume for an existing session right away. After about 10 seconds the resume failed with -32603 Internal service failure / ServiceUnavailableError. The same resume in a process without the delay succeeded at once. The script below reproduces it.

    One thing differs from your analysis: resume does already wait for activation, because attaching the session loads the ACP catalog. But that wait gives up after 5 seconds of polling plugin.list, and then model.list gives up after another 5 seconds on the server, which produces "Location plugins did not finish activating". So any activation longer than about 10 seconds (which a large $HOME, as in #55937, could easily cause) makes resume fail with an error your client can't tell apart from a real failure. With an 8-second delay, the resume blocked and then succeeded. session/new and session/load go through the same catalog load, so they are probably affected too.

    Related: #53358 (the activation wait before ACP's first catalog read) and #55937 (the $HOME-wide watcher that slows activation).

    Reproduction script (repro.py)
    #!/usr/bin/env python3
    """Reproduce #57204: ACP session/resume right after initialize fails while Location plugins activate.
    Usage: python3 repro.py [opencode command...]   (default: opencode)
    Needs ./proj/.opencode/plugins/slow.ts next to this script:
        import { Plugin } from "@opencode/plugin"
        export default Plugin.define({ id: "slow-activation", setup: async () => {
          await new Promise((r) => setTimeout(r, Number(process.env.SLOW_PLUGIN_MS ?? "0"))) } })
    SLOW_MS (default 15000) sets how long activation takes in step 2."""
    import json, os, subprocess, sys, time, threading
    HERE = os.path.dirname(os.path.abspath(__file__))
    PROJ = os.path.join(HERE, "proj")
    os.makedirs(os.path.join(PROJ, ".opencode/plugins"), exist_ok=True)
    open(os.path.join(PROJ, ".opencode/plugins/slow.ts"), "w").write('import { Plugin } from "@opencode/plugin"\nexport default Plugin.define({ id: "slow-activation", setup: async () => { await new Promise((r) => setTimeout(r, Number(process.env.SLOW_PLUGIN_MS ?? "0"))) } })\n')
    CMD = sys.argv[1:] or ["opencode"]
    
    def run(slow_ms, steps):
        env = dict(os.environ, SLOW_PLUGIN_MS=str(slow_ms))
        p = subprocess.Popen(CMD + ["acp"], cwd=PROJ, env=env, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
                             stderr=subprocess.DEVNULL, text=True, bufsize=1)
        out = {}
        def reader():
            for line in p.stdout:
                try: m = json.loads(line)
                except Exception: continue
                if "id" in m and ("result" in m or "error" in m): out[m["id"]] = m
        threading.Thread(target=reader, daemon=True).start()
        def call(i, method, params, timeout=60):
            t = time.time()
            p.stdin.write(json.dumps({"jsonrpc": "2.0", "id": i, "method": method, "params": params}) + "\n"); p.stdin.flush()
            while i not in out and time.time() - t < timeout: time.sleep(0.05)
            r = out.get(i); print(f"  {method} ({time.time()-t:.1f}s):", json.dumps(r)[:400]); return r
        try: return steps(call)
        finally: p.kill()
    
    init = {"protocolVersion": 1, "clientCapabilities": {}}
    print("1) create a session (no slow plugin)")
    r = run(0, lambda call: (call(1, "initialize", init), call(2, "session/new", {"cwd": PROJ, "mcpServers": []}))[1])
    sid = r["result"]["sessionId"]
    print("2) fresh process, slow plugin activation (SLOW_MS, default 15s); resume right after initialize")
    run(int(os.environ.get("SLOW_MS","15000")), lambda call: (call(1, "initialize", init), call(2, "session/resume", {"sessionId": sid, "cwd": PROJ, "mcpServers": []})))
    print("3) fresh process, no slow plugin; same resume")
    run(0, lambda call: (call(1, "initialize", init), call(2, "session/resume", {"sessionId": sid, "cwd": PROJ, "mcpServers": []})))

    Run it: python3 repro.py

  2. RaviTharuma commented on Oct 21, 2026

    @RaviTharuma

    Another data point on 2.1.2 (npm @opencode/cli, Linux x64), with session/new on a fresh opencode acp process and no artificial plugin delays.

    • Trigger: skill discovery. The config has about 1.3k skills in the shared agents skill directory, plus the same skills symlinked into the Claude-compatible skill directory. The debug log shows the watcher for the second skill root starting about 13s after "location services booted", and the first session/new fails at about 10s with -32603 / ServiceUnavailableError ("Location plugins did not finish activating").
    • Retry: re-sending the identical session/new 3s later succeeds (about 16–17s after initialize in total). Delaying the first request doesn't help, because the private server only starts on the first request.
    • Impact: an ACP bridge that spawns opencode acp on demand fails the first message after every spawn.
    • Workaround: a stdio proxy that re-sends session/new/load/resume on that exact error.

    #57237 would fix it for us if the bounded readiness wait covers about 20s. A way to pin a longer activation wait, or to let opencode acp use the running background service instead of a private server, would also avoid it.

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions