Skip to content

Windows Desktop MSIX: updater force-registers at quit into a live AppX container — app unlaunchable (0x80070020) until sign-out #89687

Description

@daringo42-creator

Note: this concerns the Claude Desktop app for Windows (MSIX), not the CLI — filing here as the available public channel; happy to re-route if there is a better one. The bundled Claude Code CLI is unaffected (verified: it carries no package identity).

Product: Claude Desktop for Windows (sideloaded MSIX, package family Claude_pzs8sxrjxfjjc, SignatureKind: Developer)
Environment: Windows 11 Pro, OS build 10.0.26200, x64
Versions involved: 1.28929.0 → 1.32885.1 → 1.34493.1 → 1.37937.0
Frequency: 3 of 3 self-update cycles on this machine (2026-08-19, 2026-08-19→21, 2026-08-25)
Impact: 21 min, multi-hour (needed outside tooling), and 87 min of total app unavailability; the failure mode is silent (no dialog, no error, clicking the icon does nothing)


Summary

After the in-app updater applies an update, the app cannot launch. Every activation fails at
the AppModel layer with 0x80070020 (ERROR_SHARING_VIOLATION):

Microsoft-Windows-AppModel-Runtime/Admin
id=215  0x80070020: Cannot create the Desktop AppX container for package
        Claude_<new>_x64__pzs8sxrjxfjjc because an error was encountered converting the job.
id=208  0x80070020: Cannot create the process for package Claude_<new>... [LaunchProcess]

while the shell simultaneously reports success:

Microsoft-Windows-TWinUI/Operational id=1621
Activation of app Claude_pzs8sxrjxfjjc!Claude attempted. Execution state: ...
The operation completed successfully.

So the user sees nothing at all. Re-registering, RepairAppRegistration, and reinstalling the
MSIX all succeed as operations and change nothing (measured repeatedly across all three
incidents). The only recovery is ending the user session (sign out / reboot).

Root cause chain (from AppXDeploymentServer + AppModel-Runtime logs and app main.log)

  1. The app's Desktop AppX container outlives app exits and is reused across launches.
    Measured: container {BF8B05AB-9DA6-11F1-B6AF-40D13333441E} was created 2026-08-21
    14:36:17 and received the app's main process again on 08-22 (×2), 08-23, 08-24, and 08-25
    (07:33 and 11:06) — six separate launches, each matching a Starting app line in
    main.log, with the container surviving every exit in between. A container bound to the
    old package version is therefore effectively always alive at update time.

  2. The updater stages the download correctly and even uses deferral on the Add:

    08-25 11:06:12  Deployment Add ... Claude-61bfd4a1...msix
                    Options: NormalPriorityRequest, DeferRegistrationWhenPackagesAreInUse
    
  3. But at quit, the updater forces registration immediately instead of letting that
    deferral resolve:

    main.log 14:49:07  beforeQuitForUpdate handler fired, going down for update
    AppXDeploy 14:49:07  RegisterByPackageFamilyName Claude_pzs8sxrjxfjjc
                         Options: ForceApplicationShutdownOption
    AppXDeploy 14:49:11  Register 1.34493.1.0 → 1.37937.0.0 completed (4328 ms)
    

    Registration lands ~4 s after the quit began. In incident 1, main.log's last
    process-memory sample shows 10 Electron processes still alive 21 s after
    beforeQuitForUpdate
    — shutdown of the process tree demonstrably takes longer than the
    updater waits.

  4. The old-version container survives the forced registration (incident 3: BF8B05AB
    destroyed only at 15:41, by the user's reboot). Every launch of the new version then fails
    converting the job (events 215/208 above) until the session ends.

Proof this is the updater's behavior, not a Windows/MSIX inevitability

A Store-signed MSIX app on the same machine (OpenAI Codex, family
OpenAI.Codex_2p2nqsd0c76g0) updates through the Store machinery and never hits this,
because its registrations defer instead of forcing:

08-23 00:00:10  Register OpenAI.Codex_26.818.5229 ...
                Options: RegisterHighestVersion, FailIfNeedsRemediation, LowPriorityRequest
                Result: Failed to reach state ResolvedDeferredRegistrations   ← stays staged
08-23 08:23:12  (retried — deferred again)
08-23 22:57:33  (retried — deferred again)
08-24 21:36:48  Register completed, 672 ms                                    ← quiescent

One Codex update that never found a quiet window was rolled back (DeStage,
08-21 22:14:51) rather than forced. Deferral → retry → rollback: registration never happens
while the old container is live, so relaunches never break.

Secondary defect observed (incident 2, 2026-08-19→21)

The updater trusts its own staged marker over Windows' registered state. With 1.32885.1
registered, the updater logged Staged version 1.34493.1 is still current for hours while
its temp MSIX files were zero bytes and deployment had aborted with:

0x80073D02: Unable to install because the following apps need to be closed
            Claude_pzs8sxrjxfjjc!Claude

It never re-verified against Get-AppxPackage, never re-downloaded, and never surfaced
anything. Recovery required manually downloading the MSIX (Authenticode-valid,
SHA-256 AD5EAD59...A55C), Add-AppxPackage -ForceApplicationShutdown, and a reboot.

Suggested fixes, in order of leverage

  1. Stop forcing registration in beforeQuitForUpdate. The Add already uses
    DeferRegistrationWhenPackagesAreInUse; letting that deferral resolve (as the Store does)
    removes the failure class outright. If forcing is retained, gate it on verified
    quiescence: all package-identity processes exited and no live Desktop AppX container
    for the family (AppModel-Runtime events 210/217 replay, or equivalent API).
  2. Reconcile updater state against the registered package version each cycle instead of
    the self-maintained "staged" marker; treat a zero-byte/absent staged package as
    not-staged; surface 0x80073D02 instead of looping silently.
  3. Post-update launch health check: after a self-update, if activation produces
    AppModel-Runtime event 208 with 0x80070020, show a real dialog ("sign out to finish
    updating") — currently the user gets absolute silence while the shell logs success.
  4. Minor, same subsystem: CoworkVMService logs on every start that it cannot configure or
    disarm its SCM recovery actions (open service: Access is denied, running as
    LocalSystem), warning that it "may be auto-restarted during package servicing".
  5. Diagnostic friction worth knowing: the log directory moved (~1.34493) from
    %APPDATA%\Claude\logs to %LOCALAPPDATA%\Claude\Logs; the abandoned copy keeps its last
    contents and looks like logging stopped.

Open question our instrumentation will answer

Whether the surviving container is held by unnoticed package-identity processes (child
processes the quit didn't reap) or is an AppModel bookkeeping leak with zero members. A local
watchdog now enumerates all processes via GetPackageFamilyName at block time, logs them,
kills them, and records whether the container dies. Happy to share that data from the next
occurrence.

Available on request

Full exports: Microsoft-Windows-AppXDeploymentServer/Operational,
Microsoft-Windows-AppModel-Runtime/Admin, Microsoft-Windows-TWinUI/Operational, app
main.log excerpts for all three incidents, the Codex-contrast excerpts above, a Crashpad
dump from a coincident (separate) GPU crash in incident 2, and the local watchdog scripts.

Report prepared 2026-08-25 from Windows event logs and application logs on the affected
machine; all quoted lines are verbatim.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    invalidIssue doesn't seem to be related to Claude Code

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions