You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Provider update is killed when the client's connection drops mid-update #27361
Updating providers from the app ran claude update on a remote environment. About 202 seconds in, the client's WebSocket reconnected (that server's event loop was stalled at the time). The server.updateProvider call ended as Interrupted, and T3 Code killed claude update while it was still copying the new binary into place. That left an empty version file next to a complete download, and the environment stayed on the old Claude Code version.
Diagnosis
The RPC handler runs the update directly on the request: [WS_METHODS.serverUpdateProvider]: (input) => providerMaintenanceRunner.updateProvider(input) (apps/server/src/ws.ts:2421).
The update command is spawned inside that request's scope, with Effect.addFinalizer(() => child.kill()) (apps/server/src/provider/providerMaintenanceRunner.ts:102-118). Nothing forks it out of the request.
So when the client connection drops and the request is interrupted, the finalizer kills the update process, whatever stage it is in.
Checked against v0.1.6-nightly.20261030.3904; this code is the same there.
Possible fix: run the update in a server-owned fiber that outlives the RPC (the client can re-attach to its progress), or at least make the command uninterruptible once it has started.
Steps to reproduce
Have a provider update available on a remote environment (seen with Claude Code).
Start the update from the app.
While claude update runs, drop the client's WebSocket connection (network change, or a stall long enough to trigger a reconnect).
The update ends as interrupted, claude update is killed, and the provider stays on the old version.
Version
0.1.6-nightly.20261029.3892 (remote server). Claude Code 2.1.314.
Environment
T3 Code Desktop on Linux x64 connected to a remote T3 Code server.
Evidence
Server trace: server.updateProvider span ended with exit Interrupted about 202 s after start, at the same time as the client reconnect.
After the interrupt, Claude Code's install directory held the full new download and an empty version file, and the environment still ran the old version.
Related issues
#8280 (Claude Code provider update hangs, closed) is a different failure in the same flow.
Fix applied or workaround
Run the update again with a stable connection, or run claude update in a shell on the remote host.
Filed by
Claude Opus 5.5 in Claude Code, via T3 Code triage.
Same defect on Windows with the Codex npm install: the CLI launchers are removed
What happened (T3 Code Desktop, Windows 11 ARM64, local server, Node 24.19.0, npm 11.17.0)
The app started a Codex provider update: npm install -g @openai/codex (0.165.0 to 0.166.0).
6 s later, ws.rpc.server.updateProvider ended as Interrupted ("All fibers interrupted without error", from ProviderMaintenanceRunner.runCommand / collectCommandResult). The request finalizer killed npm.
npm had already put the new package in %APPDATA%\npm\node_modules\@openai\codex and moved the old codex, codex.cmd and codex.ps1 aside (.codex-<random> names), but it had not linked the new bin shims.
Result: %APPDATA%\npm\codex.cmd (the provider's binaryPath) did not exist. The Codex provider was broken until a manual npm install -g @openai/[email protected], which linked the shims again and removed the .codex-* debris.
So on npm installs this failure is worse than an old version: the CLI disappears from PATH. #27056 (OpenCode gone from PATH after an update on Windows) may have the same cause.
Seen on the nightly of 2026-11-04 before 0.1.8-nightly.20261104.4165. The handler and the addFinalizer(() => child.kill()) are unchanged in 0.1.8-nightly.20261104.4165.
Tested fix: run the update in a detached fiber and only join it from the request
We patched the built server locally (apps/server/src/ws.ts equivalent):
(In the bundle we wrote the join by hand with Effect.callback + fiber.addObserver, the same as the internal fiberJoin, because Fiber.join is not imported in that chunk.) An interrupt of the request now only removes the join observer. The update keeps its own scope, so the 30-minute UPDATE_TIMEOUT_MS from #28132 still applies, and the command lock is released when the update ends.
Test with T3's own bundled Effect module: an "update" with addFinalizer (for child.kill) that sleeps 300 ms, forked from a caller that is interrupted after 50 ms:
original ["finalizer","caller interrupted"] (update killed, never finishes)
patched ["caller interrupted","update finished","finalizer"] (update finishes after the drop)
Normal calls still return the update result, and update errors still reach the caller. The patched server starts and runs normally.
Open point for an upstream fix: a client that reconnects does not re-attach to the running update's progress. The provider maintenance action state still shows it.
Filed by Claude Opus 5.5 in Claude Code, via T3 Code triage.
Activity
runshotgun commentedon Nov 4, 2026
Same defect on Windows with the Codex npm install: the CLI launchers are removed
What happened (T3 Code Desktop, Windows 11 ARM64, local server, Node 24.19.0, npm 11.17.0)
npm install -g @openai/codex(0.165.0 to 0.166.0).ws.rpc.server.updateProviderended asInterrupted("All fibers interrupted without error", fromProviderMaintenanceRunner.runCommand/collectCommandResult). The request finalizer killed npm.%APPDATA%\npm\node_modules\@openai\codexand moved the oldcodex,codex.cmdandcodex.ps1aside (.codex-<random>names), but it had not linked the new bin shims.%APPDATA%\npm\codex.cmd(the provider'sbinaryPath) did not exist. The Codex provider was broken until a manualnpm install -g @openai/[email protected], which linked the shims again and removed the.codex-*debris.So on npm installs this failure is worse than an old version: the CLI disappears from PATH. #27056 (OpenCode gone from PATH after an update on Windows) may have the same cause.
Trace (
server.trace.ndjson, times in UTC)Seen on the nightly of 2026-11-04 before 0.1.8-nightly.20261104.4165. The handler and the
addFinalizer(() => child.kill())are unchanged in 0.1.8-nightly.20261104.4165.Tested fix: run the update in a detached fiber and only join it from the request
We patched the built server locally (
apps/server/src/ws.tsequivalent):(In the bundle we wrote the join by hand with
Effect.callback+fiber.addObserver, the same as the internalfiberJoin, becauseFiber.joinis not imported in that chunk.) An interrupt of the request now only removes the join observer. The update keeps its own scope, so the 30-minuteUPDATE_TIMEOUT_MSfrom #28132 still applies, and the command lock is released when the update ends.Test with T3's own bundled Effect module: an "update" with
addFinalizer(forchild.kill) that sleeps 300 ms, forked from a caller that is interrupted after 50 ms:Normal calls still return the update result, and update errors still reach the caller. The patched server starts and runs normally.
Open point for an upstream fix: a client that reconnects does not re-attach to the running update's progress. The provider maintenance action state still shows it.
Filed by Claude Opus 5.5 in Claude Code, via T3 Code triage.