[BUG] Windows MSIX: CoworkVMService (StartupType=auto) blocks every desktop update, then blocks relaunch (0x80073D02 / 0x80070020)
Summary
Claude Desktop for Windows (MSIX) ships an auto-start Windows service that runs from inside its own package directory. Because it holds package identity permanently and is never stopped by quitting the app, it blocks the app's own updater — and, once an update is forced through, blocks the app from launching.
The net effect is that every release costs a reboot, and "Relaunch to update" reliably fails first.
This restates #57221 with first-hand evidence for both failure modes, including confirmation of its job-object claim.
Environment
- Windows 11 Home, build 10.0.26200
- Claude Desktop MSIX,
1.32352.1.0→1.32885.1.0 - Installed at
C:\Program Files\WindowsApps\Claude_<ver>_x64__pzs8sxrjxfjjc
Steps to reproduce
- Run Claude Desktop until an update is downloaded and staged.
- Click Relaunch to update.
Expected
The app closes, the staged package registers, the app reopens on the new version.
Actual
The app reopens on the old version with the update prompt cleared. Windows has marked the new package for deferred registration, and it never completes. Eventually the deployment engine gives up with 0x80073D02.
Root cause
AppxManifest.xml declares the service as part of the package:
<desktop6:Extension Category="windows.service"
Executable="app\resources\cowork-svc.exe"
EntryPoint="Windows.FullTrustApplication">
<desktop6:Service Name="CoworkVMService"
StartupType="auto"
StartAccount="localSystem">
StartupType="auto" means it is running at all times, independently of the app.
Evidence 1 — the blocker is the service, not the GUI
Get-AppPackageLog for the failing register, captured with zero claude.exe processes running:
Finished resolving action lists. DeploymentRequest action lists:
updateList: Claude_1.32352.1.0_... is updating to Claude_1.32885.1.0_...
Packages were not updated because affected apps are still running.
Running apps: {Claude_pzs8sxrjxfjjc!Claude}, Number of previous attempts: 1
error 0x80073D02: Unable to install because the following apps need to be closed Claude_1.32352.1.0_...
Error 0x80073D02: Failure in the ResolvedDeferredRegistrations state handler.
The "running app" Windows names here is the service. No GUI processes existed at that moment.
This is why the obvious workaround fails: Get-Process claude does not match cowork-svc.exe, so tooling reports "package is free" while it is not. Checking package identity via GetPackageFamilyName shows cowork-svc.exe holding Claude_pzs8sxrjxfjjc while every claude.exe from %APPDATA%\Claude\claude-code\ reports UNPACKAGED.
Silent precursor, in Microsoft-Windows-AppXDeploymentServer/Operational:
[658] Marking package {new} for deferred registration because {old} is still running.
Evidence 2 — the same service then blocks launch
After forcing the update through, the app would not start. Microsoft-Windows-AppModel-Runtime/Admin:
[211] Added process <cowork-svc pid> to Desktop AppX container <id> for package Claude_1.32885.1.0
[215] 0x80070020: Cannot create the Desktop AppX container for package Claude_1.32885.1.0
because an error was encountered converting the job.
[208] 0x80070020: Cannot create the process for package Claude_1.32885.1.0
because an error was encountered while configuring runtime. [LaunchProcess]
The service is added to the package's container first; the GUI's container creation then fails with ERROR_SHARING_VIOLATION. This confirms the job-object mechanism described in #57221.
Why users cannot work around it locally
Set-Service -Name CoworkVMService -StartupType Disabled→ Access is denied. Packaged services are ACL-protected.Stop-Servicesucceeds, but SCM restarts it within about a second.StartupTypeis declared in the manifest, so any forced change is reverted by the next update.
Ruled out by test, so others do not have to repeat it:
- Not elevation, not job confinement. A de-elevated launch via a Scheduled Task running as the interactive user at
RunLevel Limited, outside any job object, fails identically. - Not a crash. No application fault events; the app never starts.
What was tested, in order
| Attempt | Result |
| --- | --- |
| Kill claude.exe only, then Add-AppxPackage -Register | Fails, 0x80073D02 — service still holding |
| Stop-Service + kill all packaged processes, then register | Registers successfully |
| Launch app after that register | Fails, 0x80070020, unlaunchable |
| Reboot | App launches normally on the new version |
So stop-and-register trades one reboot for another: it applies the update but leaves the app unusable until restart. No net gain for users.
#63397 suggests Add-AppxPackage -Register ... -ForceTargetApplicationShutdown, run from a context detached from the Claude process tree (a Scheduled Task), so the deployment engine closes the package — service included — in the correct order. That looks like the right approach, but I have not had a pending update to test it against and cannot confirm it avoids the 0x80070020 state.
Suggested fix
Declare the service StartupType="manual" and have Claude Desktop start it on demand. That resolves both failure modes.
Failing that, the relaunch-to-update flow should stop CoworkVMService, wait for cowork-svc.exe to exit, apply the update, then restart the service and the app.
Related
Same underlying defect, reported across several months: #57221, #63397, #76357, #83932, #46179, #51954, #49655.
#63397 was closed as invalid / "doesn't seem to be related to Claude Code". This is a packaging defect in the Claude Desktop MSIX, and it costs every Windows user a reboot on every release.
Showing cached comments. Read the full discussion on GitHub ↗
3 Comments
Same failure on Windows 11 26100, package
Claude_1.32885.1.0_x64__pzs8sxrjxfjjc. Adding a fulllocal timeline because two details here look new relative to #53247 and #87879.
No crash is needed to produce the orphan. The app quit cleanly.
main.logrecordsbeforeQuitForUpdateat 14:34:39,AppXDeploymentServerevent 603 at 14:34:39.782 showsRegisterByPackageFamilyNamewithCallingProcess = claude.exe, and event 613 confirms the registercompleted successfully in 30,766 ms. There is no crash anywhere: zero Application Error events, zero
WER reports, and Crashpad had not been written to in three weeks. Only activation failed, 54 times.
The block is scoped to the interactive activation path, not to the package family. During the same
12-minute window,
Microsoft.DesktopAppInstallersuccessfully created a container for the incomingpackage 14 times, 300 to 400 ms after each failed user activation. So "container creation is blocked
for this family" is too broad a description of the fault. A detector built on that premise fires on
every normal update.
Timeline (local time, Windows event log):
| Time | Event |
|---|---|
| 08-18 10:13:51.505 | Container
{5EB35B0E-...}created for the supersededClaude_1.32352.0.0(AppModel-Runtime 210) || 08-18 18:44:30 | 1.32885.1 staged with
DeferRegistrationWhenPackagesAreInUse(603) || 08-20 10:43:00.572 | Last process added to
{5EB35B0E}(211) || 08-20 14:34:39 |
beforeQuitForUpdate, app quits cleanly || 08-20 14:35:09.941 | Event 67: failed with 0x5 modifying AppModel Runtime status for the old package |
| 08-20 14:35:10.445 | First
0x80070020(event 215) || 08-20 14:35:10.518 | Register finished successfully, 30,766 ms (400, 613) |
| 08-20 14:35:10 to 14:47:18 | 54 x
0x80070020, 13 repair-on-activation registrations, all reporting success || 08-20 14:48:15.511 | Manual restart initiated (System, User32, 1074) |
| 08-20 14:48:16.310 |
{5EB35B0E}destroyed in the per-user container sweep (217) || 08-20 14:51:43.793 | App healthy (201) |
Container
{5EB35B0E}survived two days and was destroyed only by the shutdown sweep. Normalteardown on this machine takes about one second.
Things that do not clear it, measured rather than assumed:
and the lock did not move. A deployment does not unload a hive mounted inside a live container.
CoworkVMServiceand force-terminatingcowork-svc: 7 attempts, 7 failures. Our own toolinglogged
serviceStopped=False, cowork=0on the last seven, so there was nothing left to stop.Retrying actively makes it worse. Each activation attempt tears down its predecessor's container
too late and mints a fresh one. Captured directly at 14:40:06: one attempt destroyed
{0A882B2F}(created by the 14:39:26 attempt), created
{0A882B51}, added a process to it, then logged two morefailures.
{0A882B51}became the next attempt's blocker.What cleared it: a restart. Also true of a second episode on this machine, 2026-07-24 14:02:04,
52 events of the same error, same ending. Other reporters say a plain sign-out is enough, which would
be much cheaper; I have not been able to test that here yet.
A discriminator that might help others confirm this quickly. Read
HKLM\SYSTEM\CurrentControlSet\Control\hivelistand count the DISTINCT\REGISTRY\WC\Silo<guid>values whose target path sits under
Claude_pzs8sxrjxfjjc\SystemAppData\Helium. On a healthy machinethis reads 2, and every other MSIX package on the same machine also reads 2 (verified against
Spotify, ChatGPT-Desktop, WidgetsPlatformRuntime, WebExperience, OfficeHub). The raw mount count is
not a useful signal on its own: healthy is 3 to 5 mounts. Using the other installed packages on the
same machine as a control group makes the reading self-interpreting.
Happy to attach a full capture (hivelist plus both AppX channels) if it lands again.
This is a better model than the one I opened with, and I think it's right. The stale-container-with-mounted-hives explanation accounts for things the "running service holds the job object" theory (#57221) cannot — in particular why stopping
CoworkVMServicechanges nothing, and why re-registration changes nothing. It also explains my own sequence: register succeeded, launch still failed, because a container from the superseded version was still live.Corroborating the hivelist discriminator
Ran it here on a healthy machine (post-reboot,
1.32885.1.0registered and running), counting DISTINCT\REGISTRY\WC\Silo<guid>values whose target path sits under<family>\SystemAppData\Helium:| package family | distinct | raw mounts |
| --- | --- | --- |
|
Claude_pzs8sxrjxfjjc| 2 | 5 || WindowsTerminal | 2 | 5 |
| YourPhone | 2 | 4 |
| Client.WebExperience | 2 | 5 |
| CrossDevice | 2 | 5 |
| Client.CBS | 2 | 3 |
| StartExperiencesApp | 2 | 5 |
| WidgetsPlatformRuntime | 2 | 5 |
| (5 further OEM/vendor packages) | 2 each | 3–5 |
13 of 13 read exactly 2, Claude included. Raw mounts span 3–5, so your point that the raw count is unusable on its own holds up. Using the other installed packages as a same-machine control group is what makes this good — it needs no healthy baseline captured in advance, so someone hitting this cold can still interpret their reading.
One caution for anyone running it: raw
hivelistvalues contain the local username and the full user SID (\Users\<name>\...,Packages\<family>\S-1-5-21-...), and the Silo GUIDs are v1 UUIDs, so they carry a MAC-derived node field. Worth scrubbing before pasting.One correction, offered tentatively
I think this may be a misread of the event text. In my capture the equivalent events named
DesktopAppInstalleras the container's own package, not Claude:That is DesktopAppInstaller being activated in its own right, which would say nothing about the state of the Claude family. Offered with low confidence — my AppModel-Runtime window has since rolled, so I am quoting the capture taken during the incident rather than re-querying, and your log may genuinely differ.
Better evidence for the same conclusion
Your conclusion still holds, and I think there is a cleaner demonstration of it in my capture. During the same failing window, a container was created successfully for the Claude family — for the service:
Same package family, same moment: container creation succeeds for the service and fails for interactive activation. That establishes "scoped to the interactive activation path, not the family" without needing DesktopAppInstaller in the argument at all.
Implication for the workaround in my original post
I pointed at
-ForceTargetApplicationShutdown(from #63397) as the promising route. Your finding that Windows ran 13 successful repair-registrations without moving the lock undercuts that, and the reason generalises: a deployment operation does not unload a hive mounted inside a live container.-ForceTargetApplicationShutdownis still a deployment operation. It may well close the package more cleanly and get the registration through — but on your evidence there is no reason to expect it to clear a container that is already stale, which is the half that actually blocks launch.If that holds, no user-space workaround gets there, and the fix has to be either
StartupType="manual"so the stale container never forms, or an update flow that tears the container down before registering.Your "retrying makes it worse" observation deserves emphasis, since it is the opposite of the natural user response — each activation mints a fresh container that becomes the next attempt's blocker. Anyone hitting this should stop clicking and sign out.
I have not been able to test whether a sign-out suffices in place of a full restart. I will report back if it recurs here.
Having now read #53247 and #87879 properly, I need to correct part of this report and point at the better threads.
This issue is largely a duplicate
1.12603through1.30096and beyond.Maintainers should feel free to close this as a duplicate of #53247. I would rather consolidate than fragment the evidence further.
Retracting the causal claim in "Evidence 2"
I wrote that the service being added to the container first, followed by failed GUI activation, "confirms the job-object mechanism described in #57221." That attribution is wrong, and I should not have leaned on #57221 — it is itself labelled
duplicate.The launch failure is not caused by the running service. Two independent tests in the other threads settle it:
CoworkVMServicestopped with PID 0, noClaude.exe, nocowork-svc.exe, novmwp.exe/vmmem.exe— still unlaunchable.The actual mechanism is a leaked container silo from the superseded package, with the package's Helium hives (
User.dat,UserClasses.dat) still mounted and no member processes. My own sequence fits that and not the service theory: registration succeeded, launch still failed.@DrRIH's find in #53247 looks like the precise moment it breaks —
AppModel-Runtime/Adminevent 67 failing0x5ACCESS_DENIED on the outgoing package's status transition (never reaching0x480000), one second before the first0x80070020on the incoming one.What in this report I still stand behind
The update-blocking half, which I think is a genuinely separate defect from the leaked silo:
0x80073D02with zeroclaude.exeprocesses running, whereGet-AppPackageLognames{Claude_pzs8sxrjxfjjc!Claude}as the still-running app. That one is the auto-start packaged service holding package identity and preventing deferred registration. It is a different failure from the silo leak that blocks launch, and conflating the two — as I did in the title — is not helpful.StartupType="manual"would address that half.Caveat on the control-group table I posted above
I measured "2 distinct Silo GUIDs across 13/13 packages" with Claude running. Reporters who unloaded while the app was stopped went to zero, and #87879 found 10 of 29 packages carry mounted hives normally. So a raw or distinct count on its own is ambiguous.
The unambiguous test is the one Ciki and AccountZero used: attempt an exclusive open (
FileShare.None) ofUser.datandUserClasses.datwhile no Claude process is running.ERROR_SHARING_VIOLATIONthere is the real signal. My table stands as evidence that raw mount counts are noise; it should not be read as a ready-made detector.Correcting my own workaround suggestion
I pointed at
-ForceTargetApplicationShutdownas promising. @Sabin-He's timeline in #53247 shows the register already running withForceApplicationShutdownOptionand the silo leaking anyway, and @Ciki confirmedAdd-AppxPackage -Registerrepairs registration without releasing the hives. So that flag does not address the blocking half.The community recovery in #53247 — SYSTEM force-unload of the leaked
\REGISTRY\WC\Silo*hives viaNtUnloadKey2withREG_FORCE_UNLOAD— is the one approach with multiple independent confirmations, and it needs no reboot or sign-out. Credit to @Ciki, @adpena and @AccountZero for working it out.Worth restating @adpena's point: a reboot is not an acceptable supported recovery path for an app update, particularly for anyone running long-lived sessions and local services. Four months and 22 comments on #53247 without a maintainer response is the part that stands out.