Skip to content

core: global skill update terminates shared service on Windows #47505

Open

Description

@zhiganov

Description

Updating three CLI-managed global skills under ~/.agents/skills from a separate process terminated an active OpenCode V2 shared service. Multiple active OpenCode sessions were interrupted.

No opencode2 service restart, stop, or configuration command was executed. The existing client automatically launched a replacement service after losing transport.

This has occurred once and has not yet been independently reproduced.

Timeline (UTC):

  • 14:44:24 — another process launched npx skills update -g
  • 14:44:33 — global skill files began being replaced; OpenCode logged its first watcher stopped
  • Over the next three seconds, the old service logged 223 watcher stops, 223 watcher starts, 881 subscriptions, and 16 skill rescans
  • 14:44:36 — last event from the old service: skills rescanned
  • 14:44:38 — client logged event stream disconnected
  • 14:44:39 — the external skill update completed successfully
  • 14:44:43 — the existing client started a replacement serve --service process

There was no clean shutdown, warning, fatal OpenCode log, Windows Error Reporting event, or OpenCode binary update around the termination.

Expected behavior is that global skill changes hot-reload without restarting the service, as described in #40954. PR #43522 also mentions one-off Bun watcher crashes that lacked a stable reproduction.

Plugins

None configured or found in local/global plugin directories.

OpenCode version

opencode2 v0.0.0-beta-19086 (beta channel)

Steps to reproduce

  • Start the managed shared OpenCode service with multiple active sessions.
  • From a separate process, update several globally installed skills under ~/.agents/skills, for example with npx skills update -g.
  • Observe whether skill-source watcher subscriptions multiply and the shared service terminates.
  • Check whether an existing client automatically starts a replacement service several seconds later.

The updater appears to replace skill directories rather than editing one file in place.

Screenshot and/or share link

No screenshot or public share link. Exact timestamped logs and the initiating local transcript are available if narrower excerpts are needed.

Operating System

Microsoft Windows 11, version 10.0.26200.9168, x64.

Terminal

Windows Terminal (TERM=xterm-256color); shell cmd.exe.

Activity

  1. Zhangyinglun commented on Sep 27, 2026

    @Zhangyinglun

    Another occurrence on Windows, this time with a native crash trace captured by the host process.

    Environment

    • OpenCode 2.0.16 (opencode.exe serve --hostname 127.0.0.1 --port <n>, managed by the OpenChamber desktop app)
    • Embedded Bun 1.4.2 (744846f84), Windows 10.0.26200 x64

    Trigger
    A shell tool call in an active session ran npx skills@latest add mattpocock/skills -g -a opencode -s '*' -y, writing 38 skills into ~/.agents/skills. The service died ~5 s later and the npx child died with it (only 24/38 skills were written). Re-running the same command on the replacement service succeeded.

    Timeline (UTC)

    • 07:30:01.7 service (uptime ~40 min) spawns the npx skills add process
    • 07:30:06.4 host loses the event stream (terminated)
    • 07:30:07.1 host health check: process exited, exitCode: 3, signalCode: null
    • 07:30:09.0 host starts a replacement server

    Crash output (stderr tail captured by the host)

    Bun v1.4.2 (744846f84) Windows x64
    Windows v10.26200
    Elapsed: 2445071ms | User: 58671ms | Sys: 18234ms
    RSS: 0.71 GB | Peak: 0.93 GB | Commit: 0.89 GB | Faults: 1084868 | Machine: 33.78 GB
    
    panic(thread 24880): Segmentation fault at address 0x1728
    oh no: Bun has crashed. This indicates a bug in Bun, not your code.
    
     https://bun.report/1.4.2/wa1744846fmhmggIuhooCCmC.bun-96394951-3cba9b8dc4fa4e45.nodes+6ECmC.bun-96394951-3cba9b8dc4fa4e45.nodeo3uECmC.bun-96394951-3cba9b8dc4fa4e45.nodeg6uLCmC.bun-96394951-3cba9b8dc4fa4e45.node4xsLCmC.bun-96394951-3cba9b8dc4fa4e45.nodeulsLCSntdll.dll8sm5CCSntdll.dllokq4CCSntdll.dlloy80BCcKERNELBASE.dlliw9iBCmC.bun-96394951-3cba9b8dc4fa4e45.nodegipLCmC.bun-96394951-3cba9b8dc4fa4e45.nodek47DCmC.bun-96394951-3cba9b8dc4fa4e45.node8ymECmC.bun-96394951-3cba9b8dc4fa4e45.nodeut8NCYKERNEL32.DLLu4mLCSntdll.dll4ulrBA2AwyL
    

    Every frame is inside the embedded native module .bun-96394951-3cba9b8dc4fa4e45.node on a non-JS thread (.node ×5 → ntdll ×3 → KERNELBASE → .node ×4 → KERNEL32 → ntdll), i.e. a completion callback dispatched on a native background thread. That module is @parcel/watcher: it contains D:\a\watcher\watcher\src\binding.cc, D:\a\watcher\watcher\build\Release\watcher.pdb and ReadDirectoryChangesW.

    Watcher churn during bulk skill writes
    The crashed service's log stops at the process spawn (presumably unflushed), but on the replacement service the same install produced repeated stop/start cycles of the ~/.agents/skills watcher within one second:

    07:32:05.132Z watcher stopped  ~/.agents/skills
    07:32:05.141Z watcher started  ~/.agents/skills   (+10 "watcher subscribe" for the same path)
    07:32:05.506Z watcher stopped  ~/.agents/skills
    07:32:05.511Z watcher started  ~/.agents/skills   (+11 "watcher subscribe")
    07:32:05.824Z watcher stopped  <project>/.claude/skills
    07:32:05.844Z watcher started  <project>/.claude/skills
    

    That run survived, so it is a race. The pattern (unsubscribe/resubscribe during an event burst, near-null fault on the watcher backend thread, intermittent) matches the Windows use-after-free in parcel-bundler/watcher#262. Related: #50594.

  2. Blind-Striker commented on Oct 9, 2026

    @Blind-Striker

    We reproduced this on a newer build, outside any desktop app and in an isolated server. Context: we were testing a skill installer that writes into the global OpenCode config.

    Environment

    • OpenCode 2.0.23 (embedded Bun v1.4.2 744846f84), Windows 11 10.0.26300 x64, NTFS
    • Plain opencode serve --hostname 127.0.0.1 --port <n> --print-logs, started directly (not through the .cmd shim, so the exit code is OpenCode's own). 5 of the secondary-volume sessions used serve --service instead; all 4 crashes were plain serve.
    • Fresh config, data, and home roots for every session (OPENCODE_CONFIG_DIR, XDG, HOME/USERPROFILE), OPENCODE_DISABLE_PROJECT_CONFIG=1, no plugins, no sessions, no model calls. The only API load was GET /api/skill: once per second for the whole session, every 200 ms after each pass until the list was stable, and in some sessions also every 100 ms during a pass.

    Workload

    • One pass adds or removes 115 skill folders (283 files) under <config>/skills/, plus 2 agent files, in 2-7 s. On install, all files are first written to a staging folder under the config directory (outside skills/) and then renamed into place one file at a time, creating skills/<name>/ as needed. On remove, each file is renamed out of skills/ into a backup folder under the config directory, then the empty skill folders are removed.
    • Most sessions ran install, remove, and install; two sessions ran 3 and 7 passes back to back. A fresh server was used for every session.

    Result

    Lab folder on Sessions Server crashes Passes started
    System volume 18 4 49
    Secondary volume 15 0 49
    • Each crash: the process exited with code 3 after a Bun panic. Faults were at 0x88 once and at heap-like addresses ending in ...0020 three times (for example 0x17BA22B0020).
    • Three crashes happened during an install pass and one during a remove pass, so removing skills also triggers it.
    • Two crashes happened 5 s and 8 s after the server started, so long uptime is not needed. Two of the four crashes happened with no API load other than the 1 s polling.
    • The writer always completed normally (exit 0). Only the server died.
    • The volume split is not statistically conclusive (one-sided Fisher exact test, p ≈ 0.07). On the system volume the same pass took about twice as long and logged about twice as many watcher stopped lines (44-56 against 18-30 per completed three-pass session). More watcher stop and restart cycles give more chances to hit the race.

    What the server logged just before a crash (the 0x88 one; the other three ended the same way)

    level=INFO message="skills rescanned" file="<config>\\skills\\<name>" skills=[...]
    level=INFO message="watcher stopped" path="<config>\\skill" type=file
    level=INFO message="watcher stopped" path="<config>\\skills" type=directory
    ============================================================
    Bun v1.4.2 (744846f84) Windows x64
    panic(thread <n>): Segmentation fault at address 0x88
    oh no: Bun has crashed. This indicates a bug in Bun, not your code.
    

    Crash report from one session: https://bun.report/1.4.2/wa1744846fkgmggIugooCCqC.bun-3579391051-3cba9b8dc4fa4e45.nodes+6ECqC.bun-3579391051-3cba9b8dc4fa4e45.nodewp3ECqC.bun-3579391051-3cba9b8dc4fa4e45.node61vECqC.bun-3579391051-3cba9b8dc4fa4e45.node2pwLCqC.bun-3579391051-3cba9b8dc4fa4e45.node4xsLCqC.bun-3579391051-3cba9b8dc4fa4e45.nodeulsLCSntdll.dll8ut5CCSntdll.dllokx4CCSntdll.dllo6n0BCcKERNELBASE.dlli3gjBCqC.bun-3579391051-3cba9b8dc4fa4e45.nodegipLCqC.bun-3579391051-3cba9b8dc4fa4e45.nodek47DCqC.bun-3579391051-3cba9b8dc4fa4e45.node8ymECqC.bun-3579391051-3cba9b8dc4fa4e45.nodeut8NCYKERNEL32.DLLu/mLCSntdll.dll4k3fA2AwI

    The frames are in the same embedded .bun-*-3cba9b8dc4fa4e45.node module as in the previous comment, and most of its frame offsets match the previous trace (s+6E, 4xsL, ulsL, gipL, k47D, 8ymE, ut8N). This looks like the same watcher race, still present in 2.0.23.

    Diagnostic note: in all 4 crashes, opencode.log contained no panic and no WARN/ERROR line, and it lost about the last 300 ms of log lines before the crash. Only the exit code and stderr show the crash. This may explain the "no fatal log" in the original report and the unflushed log in the previous comment.

    Expected, not a bug: during a pass, /api/skill returns partial lists (for example 10 → 36 → 81 → 102 of 117, including the 2 built-ins) while the watcher rescans about every 0.5 s. When the server survived, the list matched exactly within 0.6 s after the writer finished.

    Minimal repro (generic; we did not run this exact script separately)

    1. Start opencode serve with OPENCODE_CONFIG_DIR pointing to an empty folder on the system drive.
    2. Wait until GET /api/skill returns only the built-in skills.
    3. In a loop, create about 100 folders <config>/skills/test-<i>/SKILL.md (with valid name/description frontmatter, plus 1-2 extra files each), then delete them all.
    4. Watch the server process. With our installer and the lab on the system drive, it exited with code 3 during 4 of 49 passes (about 1 in 12).
  3. mradwankhalil commented on Oct 16, 2026

    @mradwankhalil
    Contributor

    Adding fresh data + two suggestions from a Windows report filed today (#56236, triaged as a duplicate of this):

    Crash: v2.0.29, Bun 1.4.2, after ~18.7 h uptime (RSS 2.15 GB / peak 2.78 GB). panic: Segmentation fault at address 0xFD8 — every crash frame is in the embedded native addon built from parcel-bundler/watcher (watcher.pdb, binding.cc, ReadDirectoryChangesW), on a non-main thread. exitCode 3; 6 busy sessions lost; the desktop host restarted the service. First crash of this kind in ~5 weeks of logs here.

    Upstream mapping: matches parcel-bundler/watcher#262 — a Windows use-after-free where unsubscribe() destroys the Subscription while a ReadDirectoryChangesW completion APC is still pending.

    Ruled out on our side: config reloads are not the trigger in this case — a controlled repro (config writes mid-turn against a mock LLM, same build) shows in-flight turns survive reloads and pick up the new config on the next turn. The churn source here was idle eviction / watch reconciliation.

    Suggestions:

    1. Track gemini "i'm finished" loop #262 and bump @parcel/watcher once it is fixed.
    2. Interim, on Windows: reuse the subscription for a path instead of unsubscribe→resubscribe (filter in JS). The churn-reduction PR fix(core): skip compatibility reloads for unrelated config writes #53764 (for core: any file write inside the config directory triggers an un-debounced compatibility reload — ~/.claude/skills watcher resubscribe loop (v2.0.23) #53393) is also relevant.

    Mitigation in use meanwhile: on the desktop side we auto-resume sessions that were busy at a crash-restart, so the user-visible impact is ~zero until the addon fix lands.

  4. ajinkyajacob commented on Oct 24, 2026

    @ajinkyajacob

    Filed #58672 for the restart storm that this panic depends on: Watcher.Service reference-counts native subscriptions per target, and the refcount blips to zero whenever a caller drops and re-subscribes a watch. Each blip closes the entry, so @parcel/watcher runs unsubscribe and the next consumer starts a fresh native subscription.

    Measured on the Windows box that reproduced this (v2.1.4, serve --service, 32 MB of logs):

    • 30,290 watcher started / watcher stopped events
    • ...\Projects\rea\.agents\skills alone: 22,039 start/stop cycles
    • stop→start gap mostly 0–0.02 s, occasionally up to ~1 s

    The PR adds a two second idle grace window so those gaps reuse the live subscription. Live A/B against the real binding, real temp dir, resubscribe 100 ms after release: dev does 2 native subscribes / 2 unsubscribes, the branch does 1 / 1.

    Being explicit about scope: this removes the stop/start churn that the native panic follows, it does not fix anything inside @parcel/watcher, and it does not reduce the repeated subscribes at their source (#53764, #55280). I have not reproduced the segfault with the patch applied — only the churn it depends on — so treat this as removing an upstream precondition rather than closing the crash.

  5. opencodejr commented on Oct 28, 2026

    @opencodejr
    Contributor

    Thanks for the detailed timeline. I tried to reproduce this on Linux: I ran opencode serve (2.2.0, since 0.0.0-beta-19086 is no longer published) with 20 global skills under ~/.agents/skills, and repeatedly replaced all of those skill directories while querying the skill list. The service stayed up and the watcher didn't go into the stop/start storm you saw.

    The crash looks specific to the Windows backend of the native file watcher. The open PR #58672 links this restart storm to a panic in that addon. Linux uses a different backend, so a maintainer with a Windows machine will need to confirm this one.

    Related:

    If you can share the log lines from just before the old service's last event, that would help: the watcher stop/start lines for ~/.agents/skills and any non-INFO lines. If it happens again on a newer beta, please mention the version here too.

  6. ajinkyajacob commented on Nov 4, 2026

    @ajinkyajacob

    Windows reproduction of this crash, with a before/after on #58672. This is a fresh reproduction on my Windows 11 box with self-built binaries (the original log has no panic text, so this is a replay of the same churn shape rather than the original service's log).

    Environment: Windows 11 10.0.22631 x64, Bun 1.4.4. Both binaries built from the same checkout with bun run script/build.ts --single --skip-web-ui --skip-install: one with packages/core/src/filesystem/watcher.ts from dev, one with #58672.

    Method: opencode --print-logs serve in a project containing .agents/skills/one/SKILL.md; warm GET /api/config; then rewrite SKILL.md on an interval. That is the skill refresh path that clears and re-registers the compatibility watches. Count watcher started / watcher stopped and watch the process exit code.

    build churn outcome native starts native stops consumer subscribes
    dev 80 cycles @ 200 ms crashed at cycle 48, exit 3 155 129 155
    #58672 80 cycles @ 200 ms survived 26 0 251
    dev 1000 cycles @ 100 ms crashed at cycle 244, exit 3 362 336 362
    #58672 1000 cycles @ 100 ms survived 26 0 1748

    The 26 starts on #58672 are all at server startup; none happen during churn.

    ~/.agents/skills specifically:

    dev,  80 cycles:   44 starts / 43 stops
    dev,  1000 cycles: 113 starts / 112 stops
    #58672, 1000 cycles: 1 start (startup) / 0 stops
    

    That is the shape from the report: one stop and a fresh native subscription per reload burst, over and over.

    Lines immediately before the crash (dev-80.crash.txt):

    timestamp=... level=INFO message="watcher stopped" path="...\project\.agents\skills" type=directory role=server
    Bun v1.4.4 (38afee6c8) Windows x64
    Windows v10.22631
    Elapsed: 10366ms | User: 1078ms | Sys: 328ms
    RSS: 0.30 GB | Peak: 0.33 GB
    
    panicked (thread 27276): Segmentation fault at address 0xFFFFFFFFFFFFFFFF
    oh no: Bun has crashed. This indicates a bug in Bun, not your code.
    

    The 1000-cycle run ends the same way: panic(thread 7952): Segmentation fault at address 0xFFFFFFFFFFFFFFFF, oh no: Bun has crashed, exit code 3. The stack frames point at the embedded native addon, and the line right before the panic is a watcher stopped for .agents\skills.

    Non-INFO lines: only the Bun crash banner (Bun v1.4.4 ..., Features:, Elapsed/RSS, panic(...), oh no: Bun has crashed). Nothing else, which matches the original log having no panic text.

    Evidence — full ANSI-stripped logs, crash excerpts, per-path event counts, and the harness: https://gist.github.com/ajinkyajacob/6c850e0084a5b1a0a7c3eb2ef6e7d2f6

    One local gotcha worth writing down: this machine sets OPENCODE_FILEWATCHER_DISABLE=1, which disables the watcher entirely. The harness overrides it to 0; without that, no watcher events occur and nothing reproduces.

  7. lazyalex616 commented on Nov 7, 2026

    @lazyalex616

    Still reproduces on 2.2.5 (latest stable, embedded Bun 1.4.4), Windows 11, managed serve --service. Adding one aspect not described above: with an attached TUI the crash becomes a restart loop, not a single lost service.

    What happened

    • A global skill with 13,089 files (hugohe3/ppt-master) was rewritten under ~/.agents/skills (all file mtimes inside 00:15:13–00:15:17 local).
    • 16:15:18Z: client logs event stream disconnected ... ECONNRESET, and the TUI shows "Restarting service… Your session will resume automatically."
    • From 16:15:29Z to 16:17:43Z the client launched 18 serve --service processes. Most lived 1–2 s. Each one's last log lines are the same: watcher subscribe / watcher started / watcher stopped on C:\Users\<user>\.agents\skills (type=directory, backend=windows), with no WARN/ERROR line. Each new service re-subscribes to the tree that is still changing and dies again.
    • The loop only stopped when the terminal hosting the TUI was closed; reopening opencode brought up a healthy service.
    • The same pattern (consecutive serve --service starts, last line a skills-dir watcher event) occurred two days earlier, at the moment the same skill was first installed.

    What I could not capture

    The service's stderr is not written to opencode.log, so I do not have the Bun panic text for this machine; the identification with this issue rests on the matching log pattern, timing and trigger, not on a captured trace. No WER event was recorded.

    Workaround in use

    OPENCODE_FILEWATCHER_DISABLE=1 in the service env (opencode service set env OPENCODE_FILEWATCHER_DISABLE 1, effective on the next service start). No crash since, at the cost of no hot reload (/reload needed after config/skill/plugin edits).

    Suggestion

    Besides #58672: the automatic service restart could back off (or stop and show the error) after N crashes within a short window. An unattended loop of 18 restarts in about two and a half minutes is harder to diagnose than a single "service crashed" message would be.

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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions