[BUG][Windows] Session restore fires a burst of concurrent taskkill /T that exhausts the WMI per-user quota (still in 2.1.295)

Status Open
Reported on v2.1.295
Maintainer reply None cached
Activity 0 comments · opened Oct 12, 2026

Summary

When Claude Desktop restores or re-spawns many Code sessions at once on Windows, a burst of taskkill.exe /PID <pid> /T /F processes runs concurrently. taskkill /T builds the process tree with a full WMI Win32_Process enumeration, so the burst turns into dozens of concurrent full enumerations. On this machine at least 94 of them failed within 10 seconds. Successful WMI calls are not logged, so the real number of calls is higher.

WMI's per-user arbitrator allows only 30 outstanding tasks per user (OutstandingTasksPerUser = 30, the default). The excess calls are cancelled (0x80041032), and while the quota is exhausted every WMI client running as the same user fails with "Call cancelled" or "Quota violation", including Claude Code's own Get-CimInstance probes.

This is the same taskkill /T → WMI amplification as #73785, #67888 and #79467 (all auto-closed as inactive, not fixed), with a different trigger (a session-restore burst instead of statusline cancellation or a runaway loop) and with the specific limit that is hit. It is still present in 2.1.295.

Environment

  • Windows 11 Home 10.0.26200 (x64)
  • Claude Code 2.1.295 (native claude.exe, spawned by Claude Desktop)
  • Claude Desktop 2.31226.1.0 (MSIX)
  • 18 concurrent Code sessions with several stdio MCP servers each, ~1,400 processes on the machine

What happened (2026-10-12, local time)

  • 12:02 — Claude Desktop re-spawns the sessions (main.log: [CCD] session spawn on required_version …, Updated session local_…).
  • 12:02:21–12:02:31 — Microsoft-Windows-WMI-Activity/Operational logs 94 × event 5858 with ResultCode 0x80041032 for

``
SELECT __PATH, ProcessId, CSName, Caption, SessionId, ThreadCount, WorkingSetSize,
KernelModeTime, UserModeTime, ParentProcessId FROM Win32_Process
``

each from a different short-lived client PID.

  • 12:02–12:23 — the same query failed 155 times from 153 distinct client PIDs (94 at 12:02, 24 at 12:03, 10 at 12:04, 12 at 12:06–12:07, 15 at 12:23).
  • None of the client PIDs was a PowerShell process at that time (cross-checked against Microsoft-Windows-PowerShell/Operational event 40961; 23 PID matches were reuse, more than 30 s apart).

Why it is taskkill /T

  • The field list above matches the UTF-16 strings in C:\Windows\System32\taskkill.exe, including ParentProcessId, which /T needs. tasklist.exe has no ParentProcessId string, and wmic.exe is not installed.
  • The 2.1.295 binary contains killProcessTree → taskkill.exe /PID <pid> /T /F. The Desktop app bundle (app.asar) references taskkill.exe in 7 places, one of them next to [CCD-SessionRecovery].
  • Not proven: which process launched these taskkill calls, the CLI's killProcessTree or the Desktop app's session recovery. Both contain the call. The client processes had exited before they could be attributed, and the WMI trace log was not enabled. Killing each session's stdio MCP server trees one taskkill /T at a time is the most likely source, but this is a hypothesis.

Which limit is hit

root:__ArbitratorConfiguration (defaults, never changed on this machine):

| Setting | Value |
|---|---|
| OutstandingTasksPerUser | 30 |
| OutstandingTasksTotal | 3000 |
| TaskThreadsPerUser | 3 |
| TotalCacheMemoryPerUser | 2048 KB |

The provider host was not the bottleneck. During a later quota episode (12:23–12:24, when Get-CimInstance Win32_Process returned "Call cancelled" and Get-WmiObject Win32_Process returned "Quota violation" for at least ~35 s), the CIMWin32 WmiPrvSE.exe used 17 MB and 291 handles, against __ProviderHostQuotaConfiguration limits of 512 MB and 4096 handles. With ~1,400 processes, each full Win32_Process enumeration is slow, so each taskkill /T holds one of the 30 per-user slots for a long time.

Impact

  • During the burst every WMI consumer running as the same user fails: Claude Code's own PowerShell Get-CimInstance Win32_Process probes (ancestors, children, creation time), the Desktop app's Get-CimInstance Win32_ComputerSystem, monitoring scripts.
  • The cost grows as sessions × servers × processes: more open sessions mean more processes for each enumeration to walk and more enumerations running at once.

Suggested fix

  • Kill the tree without WMI: take one CreateToolhelp32Snapshot (it includes th32ParentProcessID), compute the descendants and TerminateProcess them. That is one snapshot per session instead of one taskkill /T per child.
  • Or run each MCP server and Bash child inside a Job Object with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE (see also #62659) and close the job.
  • At minimum, serialize the taskkill /T calls within a session and across sessions during a restore.

Steps to reproduce

  1. On Windows, open Claude Desktop with 15 or more Code sessions, each with several stdio MCP servers.
  2. Trigger a restore or re-spawn of all sessions (app restart or a CLI version change).
  3. Run Get-WinEvent -FilterHashtable @{ LogName='Microsoft-Windows-WMI-Activity/Operational'; Id=5858 } and look for a burst of 0x80041032 for the query above within a few seconds.

---

Diagnosed by Claude Code (claude-opus-5-5) on the affected machine at the owner's request. All measurements were read-only: event logs, a process snapshot sampler and string scans of the binaries. Body corrected shortly after filing: the first version overstated the burst (it counted a 15-minute window as 2 seconds) and stated the caller as fact.

View original on GitHub ↗