[BUG] Windows MSIX: CoworkVMService (StartupType=auto) blocks every desktop update, then blocks relaunch (0x80073D02 / 0x80070020)

Status Closed — duplicate
Maintainer reply None cached
Activity 4 comments · opened Aug 20, 2026 · closed Aug 25, 2026

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.01.32885.1.0
  • Installed at C:\Program Files\WindowsApps\Claude_<ver>_x64__pzs8sxrjxfjjc

Steps to reproduce

  1. Run Claude Desktop until an update is downloaded and staged.
  2. 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 DisabledAccess is denied. Packaged services are ACL-protected.
  • Stop-Service succeeds, but SCM restarts it within about a second.
  • StartupType is 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.

View original on GitHub ↗

3 Comments

RyanBot1234 · 9 days ago

Same failure on Windows 11 26100, package Claude_1.32885.1.0_x64__pzs8sxrjxfjjc. Adding a full
local 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.log records
beforeQuitForUpdate at 14:34:39, AppXDeploymentServer event 603 at 14:34:39.782 shows
RegisterByPackageFamilyName with CallingProcess = claude.exe, and event 613 confirms the register
completed 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.DesktopAppInstaller successfully created a container for the incoming
package 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 superseded Claude_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. Normal
teardown on this machine takes about one second.

Things that do not clear it, measured rather than assumed:

  • Re-registration in any form. Windows itself ran 13 successful repair-registrations during the window

and the lock did not move. A deployment does not unload a hive mounted inside a live container.

  • Stopping CoworkVMService and force-terminating cowork-svc: 7 attempts, 7 failures. Our own tooling

logged serviceStopped=False, cowork=0 on the last seven, so there was nothing left to stop.

  • Waiting. There is no timeout. The window ended because retries stopped, not because anything released.

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 more
failures. {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\hivelist and count the DISTINCT \REGISTRY\WC\Silo<guid>
values whose target path sits under Claude_pzs8sxrjxfjjc\SystemAppData\Helium. On a healthy machine
this 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.

sstangle73 · 9 days ago

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 CoworkVMService changes 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.0 registered 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 hivelist values 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

Microsoft.DesktopAppInstaller successfully created a container for the incoming package 14 times

I think this may be a misread of the event text. In my capture the equivalent events named DesktopAppInstaller as the container's own package, not Claude:

[210] Created Desktop AppX container {...} for package Microsoft.DesktopAppInstaller_1.29.280.0_x64__8wekyb3d8bbwe
[211] Added process <pid> to Desktop AppX container {...} for package Microsoft.DesktopAppInstaller_...
[217] Destroyed Desktop AppX container {...} for package Microsoft.DesktopAppInstaller_...

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:

[210] Created Desktop AppX container {A} for package Claude_1.32885.1.0_x64__pzs8sxrjxfjjc
[211] Added process <cowork-svc pid> to Desktop AppX container {A} 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 ... [LaunchProcess]

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. -ForceTargetApplicationShutdown is 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.

sstangle73 · 9 days ago

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

  • #53247 is the canonical thread for the launch failure — open since 2026-04-25, 22 comments, reproduced continuously from 1.12603 through 1.30096 and beyond.
  • #87879 is a better-scoped report of the same launch failure than mine, filed ~17 hours before this one.

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:

  • #87879 killed all package processes and relaunched: fails with zero package processes running.
  • AccountZero in #53247: CoworkVMService stopped with PID 0, no Claude.exe, no cowork-svc.exe, no vmwp.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/Admin event 67 failing 0x5 ACCESS_DENIED on the outgoing package's status transition (never reaching 0x480000), one second before the first 0x80070020 on 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:

0x80073D02 with zero claude.exe processes running, where Get-AppPackageLog names {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) of User.dat and UserClasses.dat while no Claude process is running. ERROR_SHARING_VIOLATION there 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 -ForceTargetApplicationShutdown as promising. @Sabin-He's timeline in #53247 shows the register already running with ForceApplicationShutdownOption and the silo leaking anyway, and @Ciki confirmed Add-AppxPackage -Register repairs 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 via NtUnloadKey2 with REG_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.

Showing cached comments. Read the full discussion on GitHub ↗