Skip to content

Desktop sidecar startup blocks for 2+ minutes on large database, causing "Cannot connect to local server" (v1.17.12 regression) #35514

Description

@nanfang-wuyu

Description

Desktop sidecar startup blocks for 2+ minutes on large database, causing "Cannot connect to local server" (v1.17.12 regression)

Environment

  • Desktop version: v1.17.13 (upgraded from v1.17.11)
  • OS: Linux x86_64 (Ubuntu 24.04.4 LTS)
  • Electron: 42.3.3
  • opencode.db size: 848 MB
    • 551 sessions, 47,729 messages, 195,332 parts, 97,010 events
  • Configured plugins: openai-ws-custom.ts, superpowers@git+https://github.com/obra/superpowers.git
  • Concurrent CLI instances: 5 (sharing the same database via WAL mode)

Problem

After updating from v1.17.11 to v1.17.13, the desktop app shows "Cannot connect to local server" for approximately 2–3 minutes on every launch, then recovers on its own. v1.17.11 started up in ~3 seconds with no issues.

Root Cause Analysis

Startup sequence (from index.js + sidecar.js)

  1. Main process spawns sidecar via utilityProcess.fork("sidecar.js") (Electron NodeService)
  2. Sidecar imports the 20 MB bundled server module, starts HTTP server, posts { type: "ready" }this takes ~3 seconds (confirmed in main.log)
  3. Main process begins polling health check (checkHealth) every 100 ms with a 5-second timeout per attempt (line 2182)
  4. If health check fails, UI shows "Cannot connect to local server"

The blocking

  • After posting "ready", the NodeService process spikes to 100% CPU for ~2 minutes 10 seconds (observed via ps/top)
  • Since Node.js is single-threaded, the HTTP server cannot process incoming requests while the event loop is blocked
  • The health check (GET / with auth, 5s timeout) repeatedly times out during this period
  • After ~2 minutes, CPU drops to 0% and the server becomes responsive (confirmed: curl http://127.0.0.1:<port>/ returns 401 in 0.7ms)

What changed in v1.17.12 (regression introduced)

The v1.17.12 release notes include these new startup tasks:

Change Impact
"Restore session runtime operations such as event streaming, interrupts, and message lookup" Loads/restores all sessions at startup — queries 551 sessions, 47K messages, 195K parts from the 848 MB database
"Refresh cached remote skills" Re-parses all remote skill caches at startup (30+ skills across global, superpowers, and workspace scopes)
"Add paged durable session history" New session history feature requiring database operations at startup
"Keep session pages in sync during concurrent events" Session page synchronization

These tasks run synchronously on the event loop after the HTTP server starts listening, blocking all request processing.

Aggravating factor: database lock contention

  • 7 concurrent CLI instances share the same 848 MB database in WAL mode
  • WAL checkpoint is blocked: PRAGMA wal_checkpoint(TRUNCATE) returns 1|944|944 (cannot complete due to concurrent readers/writers)
  • The sidecar's database layer sets PRAGMA busy_timeout = 5000 (5s), but the blocking is CPU-bound (synchronous processing), not I/O-bound

Evidence

main.log (v1.17.13, current)

[2026-07-06 13:04:06.159] [info] app starting { version: '1.17.13', packaged: true, onboardingTest: false }
[2026-07-06 13:04:07.703] [info]   sidecar connection started { url: 'http://127.0.0.1:33661' }
[2026-07-06 13:04:07.704] [info]   spawning sidecar { url: 'http://127.0.0.1:33661' }
[2026-07-06 13:04:09.008] [info]   server ready { url: 'http://127.0.0.1:33661' }

Server reports "ready" in ~3 seconds, but the UI health check doesn't succeed until ~2 minutes later.

Process CPU (v1.17.13)

PID    %CPU  %MEM  STAT  STARTED    ELAPSED  COMMAND
2038532 102   0.8   Sl    13:04      1:30    ai.opencode.desktop --type=utility --utility-sub-type=node.mojom.NodeService

NodeService at 102% CPU for 2+ minutes after "server ready". After ~2 min:

PID    %CPU  %MEM  STAT  STARTED    ELAPSED  COMMAND
2038532 0.0   0.8   S     13:04      2:10    ai.opencode.desktop --type=utility --utility-sub-type=node.mojom.NodeService

main.log (v1.17.11, previous day — no issue)

[2026-07-05 12:26:58.914] [info] app starting { version: '1.17.11', packaged: true, onboardingTest: false }
[2026-07-05 12:27:00.476] [info]   sidecar connection started { url: 'http://127.0.0.1:41429' }
[2026-07-05 12:27:01.801] [info]   server ready { url: 'http://127.0.0.1:41429' }

No high CPU, UI connected immediately after "server ready".

Health check behavior

  • During blocking: curl -m 5 http://127.0.0.1:33661/ → timeout (event loop blocked)
  • After recovery: curl -m 5 http://127.0.0.1:33661/ → HTTP 401 in 0.7ms (server responsive)

Database state

$ sqlite3 opencode.db "PRAGMA wal_checkpoint(TRUNCATE);"
1|944|944    -- checkpoint blocked (1 = cannot complete)

$ sqlite3 opencode.db "PRAGMA journal_mode;"
wal

-- Table row counts:
-- session: 551
-- message: 47,729
-- event: 97,010
-- part: 195,332
-- todo: 210

Relevant source code (index.js)

const SIDECAR_START_STALL_TIMEOUT = 6e4;  // 60s — only for "ready" message, not health check
const TIMEOUT = 5e3;  // 5s health check timeout

// Health check loop (lines 2179-2187):
const ready = async () => {
  while (true) {
    await new Promise(resolve => setTimeout(resolve, 100));
    if (await checkHealth(url, password)) {
      healthy = true;
      return;
    }
  }
};

The health check loops indefinitely with no progress indicator or extended timeout.

Workaround

  • Wait 2–3 minutes after launching; the server becomes responsive once startup processing completes.
  • Reduce concurrent CLI instances to decrease database lock contention.
  • Downgrade to v1.17.11 (confirmed working).

Suggested Fixes

  1. Make session runtime restoration / skill refresh asynchronous — do not block the event loop. Use setImmediate / queueMicrotask chunking or move to a worker thread.
  2. Defer heavy startup tasks until after the first successful health check, so the UI connects immediately.
  3. Add a progress indicator for the health check loop instead of showing a generic "Cannot connect" error.
  4. Increase health check timeout or add a "connecting..." state with retry progress.
  5. Paginate / lazy-load sessions at startup instead of restoring all 551 sessions eagerly.
  6. Consider a dedicated worker thread for database-heavy initialization to keep the HTTP event loop responsive.

Reproduction

  1. Accumulate a large opencode database (500+ sessions, 848MB+)
  2. Have 5+ concurrent CLI instances running (sharing the database)
  3. Launch OpenCode Desktop v1.17.12 or v1.17.13
  4. Observe "Cannot connect to local server" for 2+ minutes
  5. Compare with v1.17.11 — connects in ~3 seconds

Plugins

No response

OpenCode version

No response

Steps to reproduce

  1. Accumulate a large opencode database (500+ sessions, 848MB+)
  2. Have 5+ concurrent CLI instances running (sharing the database)
  3. Launch OpenCode Desktop v1.17.12 or v1.17.13
  4. Observe "Cannot connect to local server" for 2+ minutes
  5. Compare with v1.17.11 — connects in ~3 seconds

Screenshot and/or share link

No response

Operating System

Linux x86_64 (Ubuntu 24.04.4 LTS)

Terminal

No response

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions