Windows desktop: stealth update leaves orphaned processes holding old AppX container; new version unlaunchable (0x80070020) until reboot
## Summary
The Windows desktop app's stealth auto-update leaves orphaned child processes that keep the OLD version's Desktop AppX container alive. Every launch of the NEW version then fails with 0x80070020 ("error encountered converting the job") until the machine is rebooted. The app appears simply dead to the user: clicking the icon does nothing.
This machine has hit the "update leaves Claude unlaunchable until reboot" state repeatedly across multiple update cycles (an earlier episode instead showed a "Another program is currently using this file" installer dialog while popped-out session processes were still running).
Environment
- Windows 11 Home 10.0.26200
- Claude desktop app (MSIX, package family
Claude_pzs8sxrjxfjjc) updating 1.34493.1.0 -> 1.37937.0.0 - Multiple Claude Code sessions / popout panes typically open at update time
Timeline (from Windows event logs, 2026-08-25, all times local)
- 13:37 - AppXDeploymentServer: Add operation for 1.37937 with
DeferRegistrationWhenPackagesAreInUse; event 658 "Marking package for deferred registration because Claude_1.34493.1.0 is still running". Normal. - 19:57:18 -
RegisterByPackageFamilyNamewithForceApplicationShutdownOption. Old version's container destroyed, registration finished successfully at 19:57:51 (event 400). - 19:57:51 onward - every relaunch of the new version logs (AppModel-Runtime/Admin):
- event 211 "Added process <pid> to Desktop AppX container ..." (main process starts)
- then repeated event 215
0x80070020: Cannot create the Desktop AppX container for package Claude_1.37937.0.0 because an error was encountered converting the job. - then event 208
0x80070020: Cannot create the process ... error encountered while configuring runtime. [LaunchProcess]
The app dies silently. This repeats identically at 20:01:31, 20:01:32, 20:01:51, 20:02:11, 20:02:38 (including two automatic re-register/repair passes, both of which "finished successfully" per event 400 yet launches kept failing).
- At this point no process named claude.exe existed (verified by an external kill script that logged
taskkill /IM claude.exe-> "process not found"). Something else - an orphaned child (conhost/node/shell) without package identity - was evidently still a member of the old container's job: at 20:03:02, during shutdown, the system logged event 217 destroying a Desktop AppX container for the old package 1.34493.1.0 that had been alive the whole time. - Reboot at 20:03:22; first launch at 20:03:47 succeeded instantly.
Analysis
beforeQuitForUpdate/ stealth update takes down the main app, but child processes spawned by Claude Code sessions (shells, MCP servers, console hosts) can outlive it. They hold membership in the old version's AppX container job.- The new version's container creation then fails at job conversion with
0x80070020until that job is gone. Since these survivors have no package identity and are not named claude.exe, neither Task Manager's "Claude" group nortasklist /appssurfaces them; a reboot is the only user-discoverable cure. - Suggested fix: before (or after)
quitForUpdate, enumerate and terminate all processes in the app's own container/job (the app owns the job handle, so it can do this reliably), or make the post-update launcher detect0x80070020and clean up the stale container instead of dying silently.
Repro conditions
Not 100% deterministic, but has occurred repeatedly on this machine: several Claude Code sessions with popout panes + background child processes open, stealth update fires after idle timeout, swap succeeds, relaunch fails until reboot.
6 Comments
Corroborating forensics from a second machine — same package family, same 1.34493.1.0 → 1.37937.0.0 transition — plus two findings that may help whoever fixes this:
Environment: Windows 11 Pro 10.0.26200,
Claude_pzs8sxrjxfjjc, multiple Claude Code sessions open at update time.Timeline (local time, from event logs):
Claude(CoworkVMService) start type changed auto→disabled; 7045: service (re)installed from theClaude_1.37937.0.0path.0x80070020: Cannot create the Desktop AppX container for package Claude_1.37937.0.0 … an error was encountered converting the job.App icon dead from here on ("Another program is currently using this file" dialog).DeferRegistrationWhenPackagesAreInUse(event 658: "deferred registration because 1.37937.0.0 is still running") — the same trap is armed for the next quit/relaunch.(Correction: the first version of this comment claimed recovery happened without a reboot. That was wrong — the boot record shows a user-initiated restart at 00:40, which is what cleared the lock.)
Finding 1 — the packaged service is stoppable by any authenticated user; a mitigation path exists today.
sc sdshow CoworkVMServicereturns:The first ACE grants Authenticated Users RP (start) and WP (stop); the DACL only reserves delete/reconfigure for the service SID. So the updater — or the app itself at quit time, unelevated — could stop
CoworkVMService(and reap any surviving processes of the outgoing package version, e.g.chrome-native-host.exeor elevated Claude Code children — cf. #84792, #73107, #53247) before completing deferred registration and relaunching. Reports that "admin can't touch the service" concern delete/config, not stop. Whether a service stop alone releases the pinned container job (vs. also needing the orphan reap) is untested on this machine — #80286 suggests stop alone may not suffice once the silo is wedged.Finding 2 — the manifest declares the service with a named-pipe trigger,
windows.service+localSystemServices/packagedServicescapabilities and<desktop6:DataItem Value="\pipe\cowork-vm-service" />, so the service can be demand-started after the swap; keeping it alive across the package transition is what pins the old container job and producesERROR_SHARING_VIOLATIONat container-job conversion.Cross-refs with the same signature: #89687, #84435, #80286, #73694. This has been reported since March/April (#45489, #47877, #36466, #48003) — all four were auto-closed by the dedupe bot and locked while the defect stayed alive; please keep this one open.
Field update — the obvious mitigation does NOT work. Stopping CoworkVMService + killing package processes at failure time was tried automatically 4× during a real occurrence today and the launch kept failing; only a reboot recovered.
Since my earlier comment I had installed an automated mitigation on this machine: a scheduled task triggered by AppModel-Runtime event 215 that (a) kills any process still running from an old
WindowsApps\Claude_*directory and (b) stopsCoworkVMService(permitted to Authenticated Users by the service DACL, per my earlier comment). Today it met a real occurrence:0x80070020"error … converting the job" forClaude_1.37937.2.0.WindowsApps\Claude_*directory at failure time, andStop-Service CoworkVMServicesucceeded on every run — yet the very next launch failed identically. (An external agent attempting manual recovery in parallel also failed.)So at failure time, whatever pins the old container job is not a visible package-path process, and it is not (only) the running service — stopping the service demonstrably does not release the wedged job/silo. This kills the simplest in-app fix ("stop the service before registering") as a complete solution, though it may still be necessary.
Post-recovery baseline on this machine: the Cowork VM runs as
vmmem+vmwp— Host Compute System processes living outside the package directory, invisible to any package-path-based cleanup, and not children of the app. Whether that compute system survives app quit and is what pins the container silo is the open question — it would be consistent with the HCS shutdown failures reported in #83494. I have instrumented the next occurrence: on event 215 the machine now captures a full inventory (package processes,claude/cowork-svc/chrome-native-host/vmmem/vmwpprocess list,hcsdiag listunder an elevated task, service state) before attempting anything. I will post that forensic snapshot when the bug next fires.For the fix: whatever quit-time/update-time path Anthropic implements, it apparently must also tear down the Cowork HCS compute system (and verify the container silo is actually gone), not merely stop
CoworkVMService.Independent reproduction of the same failure signature, adding one data point this thread doesn't have yet: an external recovery script that killed every process named
claude, deleted the Electron singleton lockfiles, and restartedCoworkVMServicedid not recover the app — only a full reboot did (both occurrences).Environment
Claude_pzs8sxrjxfjjc, updating 1.37937.2.0 → 1.37937.3.0Timeline (2026-08-27, local time)
[stealth-update] Triggering stealth update after idle timeout→beforeQuitForUpdate handler fired, going down for update→ log ends and never resumes0x80070020: Cannot create the Desktop AppX container for package Claude_1.37937.3.0_x64__pzs8sxrjxfjjc because an error was encountered converting the job.followed by event 208 ([LaunchProcess]fails with the same code)0x80070020pair and no app process ever appearsWhat did not recover it (run between the manual launch attempts):
Stop-Process -Forceon every process namedclaude(both theWindowsAppspath and the bundled claude-code path)%APPDATA%\Claude\lockfileand the LocalCache copyCoworkVMService(elevated)No crash dumps (Crashpad
reportsempty) and no Application-log errors from the app itself — the new version simply never gets a process off the ground. This is consistent with the orphaned-job analysis in the OP and with the helper-process root-cause trace in #89648: whatever survives isn't namedclaude, so name-based kills don't clear the old container's job.Prior occurrence on the same machine: 2026-08-21, updating 1.34493.0.0 → 1.34493.1.0 — main.log ends at 15:28:26 with the same
beforeQuitForUpdatesequence; 4 manual launches over the following ~3 hours all no-op'd (same repeated-Register pattern in AppXDeploymentServer); recovered by the machine's scheduled 05:00 reboot the next morning.Happy to pull more log detail from this machine if useful.
Forensic snapshot captured during a live occurrence, as promised — the pinner is identified: an orphaned
chrome-native-host.exefrom the previous container epoch, living in the package's AppData profile (not the install dir). Sign-out cured it without a reboot. The Cowork-VM hypothesis is dead:hcsdiag listwas EMPTY during the failure.Timeline 2026-08-28 (local, Windows 11 Pro 26200, same machine as my comments above):
0x80070020"error … converting the job" for 1.40609.0.0.cowork-svc.exefreshly spawned by the launch attempt itself. It was killed andCoworkVMServicestopped successfully — did not cure.hcsdiag list(elevated): empty — no Host Compute System VMs existed, ruling out the Cowork VM as the pinner.chrome-native-host.exePID 26392, running since 2026-08-26 17:26:41 — two days and two version transitions old — at%LOCALAPPDATA%\Packages\Claude_pzs8sxrjxfjjc\LocalCache\Roaming\Claude\ChromeNativeHost\chrome-native-host.exe. It lives in the package data profile, outsideWindowsApps, so package-dir-based cleanup (mine, and apparently the updater's) never touches it.chrome-native-host.exespawns ~6 s after the app starts — consistent with an app-managed helper that is never reaped on quit/update.Conclusion (matches #84792 and #73107): the app leaves
chrome-native-host.exerunning after quit; as a leftover member of the old version's AppX container job/silo it blocks the new container's job conversion withERROR_SHARING_VIOLATIONuntil it dies. Sign-out kills session processes — hence the cure; reboot was never actually necessary.Suggested fix: the quit/update path must terminate ChromeNativeHost (and any other helpers running from the package data profile) before completing registration, and verify the old container job is actually gone before relaunching.
My local mitigation now also reaps package-profile processes on event 215; I will report whether that makes the second click succeed without sign-out at the next occurrence.
Recurred 2026-08-28, updating 1.37937.3.0 -> 1.40609.0.0 — with new evidence that the container-keeper is not any obvious process.
Same signature: after the update swap, every launch of the new version failed with event 215/208
0x80070020 ... error encountered converting the job(AppModel-Runtime/Admin, 20:20:46–20:21:13), and at shutdown (20:21:49) Windows logged destroying a Desktop AppX container belonging to the old version 1.37937.3.0 that had been alive throughout. Reboot at 20:22 fixed it; first post-boot launch succeeded instantly.New data point: this time an external cleanup script swept aggressively between launch attempts and the failure still persisted. The sweep force-killed (a) all
claude.exe, (b) every process whose command line references the package/appdata paths (caught acmd.exeand achrome-native-host.exe), and (c) verified viaGetPackageFullNamethat zero remaining processes carried Claude package identity. Launches still failed with 0x80070020 afterwards.So the old container's job is being kept alive by something with a generic name, a generic command line, and either no queryable package identity or protection from user-level OpenProcess — plausibly a
RuntimeBroker/dllhost/backgroundTaskHostinstance or a leaked kernel job handle. From the user side this is effectively undiagnosable and unkillable; reboot is the only recovery.This strengthens the case that the fix needs to live in the app/updater: terminate all members of the app's own container job on
quitForUpdate(the app owns the job handle), or have the post-update launcher detect 0x80070020 and tear down the stale container rather than dying silently — the user just sees a dead icon.Kernel-level mechanism confirmed + an in-place recovery that needs neither reboot nor sign-out — verified while the pinning process was still alive.
Environment: Windows 11 x64 10.0.26200,
Claude_pzs8sxrjxfjjc1.37937.1.0 → 1.37937.3.0. Update staged 08-27 05:00 (deferred registration, app running), force-registered 05:10; every launch for the next two days died with AppModel-Runtime 215/2080x80070020, including after twoRegisterByPackageFullName … RepairAppRegistrationOptionpasses that each "finished successfully".What exactly stays pinned: the package's Helium registry hives, still mounted in the dead container's silo
What "error encountered converting the job" actually trips on (open question in this thread): during the failure, the package's virtual-registry hive files are exclusively locked:
%LOCALAPPDATA%\Packages\Claude_pzs8sxrjxfjjc\SystemAppData\Helium\User.dat%LOCALAPPDATA%\Packages\Claude_pzs8sxrjxfjjc\SystemAppData\Helium\UserClasses.datRestart Manager names the holders as
System(PID 4) andRegistry(PID 468) — no user-mode process holds file handles. The hives are still loaded in the kernel registry, mounted under the OLD container epoch's silo.HKLM\SYSTEM\CurrentControlSet\Control\hivelistshows it directly:Launching the new version = creating a new container = mounting those same hive files →
ERROR_SHARING_VIOLATION→ the "Another program is currently using this file" box (the dialog shows the current Claude.exe path only because the error surfaces from container setup — the exe itself opens fine with any sharing mode during the failure).Consistent with the forensic snapshot above, the only surviving pre-update-epoch process on my machine was an orphaned
chrome-native-host.exe(plus itscmd.exepipe wrapper), spawned by Chrome three days before the update from%LOCALAPPDATA%\Packages\Claude_pzs8sxrjxfjjc\LocalCache\Roaming\Claude\ChromeNativeHost\. Two details that explain why kill-script mitigations reported here didn't work:WindowsApps\Claude_*path misses it;handle64 -aon the silo name finds nothing; only its own CWD) — it pins the silo purely by job/silo membership, so handle-hunting also misses it.In-place recovery (no reboot, no sign-out), verified live
With
SeRestorePrivilegeenabled,NtUnloadKey2(…, REG_FORCE_UNLOAD)on the stale Claude entries inhivelistreleases the hive files instantly; the next launch built a fresh container and the app started normally. Notably, I did not kill the pinningchrome-native-host.exe— it is still running now, harmlessly, next to the working app. So this recovery works even when the silo member can't be found at all.Unload results for the five stale mounts:
i.e. only the
user_sid/user_classes/software/commounts of the dead silo actually block container creation.PoC (elevated PowerShell):
One more corroborating detail: stopping
CoworkVMServicedoes not release these hives (matches the field reports above) — and every launch attempt and every Repair pass reinstalls and restarts it (paired SCM 7045/7040 events each time, new PID each time), which is part of why "Repair" never helps.Fix-wise this supports what's already been suggested: before registering the staged package, the updater should tear down all members of the package's container silo(s) — explicitly including Chrome-owned native-messaging hosts under
LocalCache\Roaming\Claude\ChromeNativeHost— or, failing that, force-unload the package's stale\REGISTRY\WC\Silo*mounts exactly as above instead of leaving the user to reboot.