Windows/MSIX: staged update applied with ForceApplicationShutdown kills a live remote-controlled session; relaunch does not re-arm remote control

Status Open
Reported on v2.1.229
Maintainer reply None cached
Activity 0 comments · opened Aug 15, 2026

Preflight

Searched existing issues. Related but distinct:

  • #84650 — Windows MSIX force-kill via Remove ×2 (fail) → Add from %TEMP% .msix. This report is a different update path: a package staged hours earlier, then applied with RegisterByPackageFamilyName. No Remove attempts, no %TEMP% source, and the operation succeeds.
  • #85413 — same user-facing scenario (away from machine, long jobs killed, no opt-out) but macOS/ShipIt.
  • #84793 — remote control not re-armed after update-resume, macOS.

This is the Windows/MSIX case, plus confirmation that #84793's re-arm failure also occurs on Windows.

Environment

  • Windows 11 Pro 10.0.26200
  • Claude Desktop MSIX 1.30096.1.0 → 1.30096.5.0 (SignatureKind: Developer, publisher CN="Anthropic, PBC" — sideloaded, not Store)
  • Hosted Claude Code 2.1.229
  • Session driven by Remote Control from a phone; local work = multi-hour GPU render batches against a local ComfyUI server

What happened

The desktop app force-terminated itself to apply an update while it was hosting an active, remote-controlled session. I was away from the machine. The app relaunched itself in two seconds — but the remote binding did not come back, so there was no way to reconnect until I was physically at the PC hours later.

Nothing was executing at the instant of the kill; the session was idle, mid-review of a finished render batch. The harm here is loss of reachability, not lost compute — the machine came back up looking healthy and stayed unreachable for the rest of the day.

Earlier the same afternoon I had seen the update was pending and deliberately chose not to restart, because renders were running. The force path removes that choice regardless of what the user decided.

Timeline (local, UTC+1)

13:20:08  App launched (1.30096.1.0). Package folder Claude_1.30096.5.0_* created
          13:20:41 — update staged on disk.
13:22:46  Claude Code session starts, remote control bound.
17:16:05  Last render output written.
17:16:57  Last session activity.

-- 4h 06m after staging --

17:26:59  Event 603: "Started deployment RegisterByPackageFamilyName operation on a
          package with main parameter Claude_pzs8sxrjxfjjc and Options
          ForceApplicationShutdownOption and 0."
17:26:59  Event 855: "Claude_1.30096.1.0_x64__pzs8sxrjxfjjc is updating to
          Claude_1.30096.5.0_x64__pzs8sxrjxfjjc."
17:27:29  Event 9648/9650: "TerminateSingleService for update successful for service
          ... in package CoworkVMService, terminateService: true."
17:27:30  Event 400: "Deployment Register operation ... finished successfully."
17:27:32  cowork_vm_node.log: "[VM:start] Beginning startup" — app relaunched.
17:27:36  Session transcript loaded. Never written to again.

Source: Microsoft-Windows-AppXDeploymentServer/Operational, and
%APPDATA%\Claude\logs\cowork_vm_node.log.

Evidence the kill was not a crash or a clean exit

  • cowork_vm_node.log writes [VM:shutdown] App quit, stopping VM on every clean exit. There is no such line before the 17:27:32 start — so the 13:20 process did not exit. (For contrast, a genuine user-initiated quit later the same day logged it: 21:01:48 [VM:shutdown] App quit.)
  • %APPDATA%\Claude\Crashpad\reports\ is empty — not a crash.
  • The AppX log names the cause directly: ForceApplicationShutdownOption.

Why this is a defect, not just unlucky timing

  1. The force flag is opt-in, and the platform default is the safe one. Without DeploymentOptions.ForceApplicationShutdown, a register against a running package fails with ERROR_INSTALL_PACKAGE_IN_USE and applies on next launch. The updater explicitly asked to kill the app.
  2. A four-hour deferral window was available, and idle was not a safe signal. The package was fully staged at 13:20:41 and not applied until 17:26:59 — 4h 06m later, consistent with the documented ~4-hour update check.

What triggered application at that moment cannot be determined from these logs. Two readings fit equally:

  • Pure timer. The check came due and applied the staged package regardless of session state.
  • Timer plus an idle gate. The kill landed 10m 02s after the session's last activity (17:16:57 → 17:26:59), which looks deliberate rather than coincidental. Earlier quiet spells of 22.2, 17.8, 16.8, 16.3, 12.1 and 11.2 minutes passed without application, but no check would have been due during them, so they don't discriminate.

The ask is the same under either. If it is a pure timer, the updater needs to consult session state. If it is already idle-gated, the gate is measuring the wrong thing: on a session driven by Remote Control, "no input for 10 minutes" most often means the user is away from the machine — precisely the case where killing the session is least recoverable. Here it meant I had stepped out mid-review. An idle remote session is a waiting session, not a finished one.

  1. The app knows it is hosting a live remote-controlled session. %APPDATA%\Claude\bridge-state.json holds the binding (enabled: true, userConsented: true, remoteSessionId). That state is available to the updater's own process.
  2. Auto-relaunch does not restore reachability. The app came back in 2 seconds, but the resumed session did not re-arm remote control — the same failure #84793 reports on macOS, now on Windows. Auto-relaunch without re-arming is worse than not relaunching: the machine looks healthy while remaining unreachable.
  3. Any child processes would have gone too. Nothing was in flight at 17:27 in this instance, so nothing was lost — but processes spawned by the session are killed with the app. If the trigger is idle-gated on session input, a long-running background job is invisible to that gate: the session looks idle precisely while the work runs unattended.

What should happen

  • Do not pass ForceApplicationShutdown while a session is live. Defer registration; the staged package costs nothing sitting on disk, as the 4-hour gap here demonstrates.
  • Re-arm remote control on the update-resume path (#84793), so an unavoidable restart is at least recoverable from a phone.
  • Provide a supported opt-out. As #85413 notes for macOS, autoUpdates / DISABLE_AUTOUPDATER are Claude Code CLI settings and do not govern the desktop updater. I checked %APPDATA%\Claude\config.json, Preferences, and the app UI — there is no setting for this on Windows either.
  • At minimum, warn before killing. A prompt with "restart now / after this session" would have avoided every consequence above, since I already knew the update was pending.

Repro

  1. On Windows, start a Claude Code session in the desktop app and enable Remote Control.
  2. Leave the machine and drive the session from a phone.
  3. Wait for a staged update to be applied (here, ~4h after staging, ~10 min after the session's last input).
  4. Observe: app force-terminated and relaunched, session resumed without remote control, and no way to restore it from the phone. Any child processes the session had spawned are gone.

Happy to supply the full AppX event export or the app logs.

View original on GitHub ↗