[BUG] Claude code wsl2 freeze issue

Resolved 💬 3 comments Opened Feb 21, 2026 by GangsubLim Closed Feb 21, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Claude Code on WSL2 freezes for 20-40 seconds in specific situations:

  • Startup — TUI takes 20-40s to become responsive after launch (7+ repeated calls)
  • After exiting commands — e.g. pressing Esc to back out of /plugin, /model, etc. (~2-3s, single call)
  • On /exit — ~2-3s hang before session closes (single call)

The root cause is repeated uncached powershell.exe invocations to resolve $env:USERPROFILE. Each PowerShell cold start takes ~2.5s due to .NET runtime and profile loading, and this is called 7+ times without caching the result.

This provides the strace-level root cause analysis that was missing from previous reports of the same issue:

  • #7182 — "Incredibly slow performance (PowerShell freezes main thread)"
  • #22970 — Meta issue tracking Windows/WSL freeze reports
  • #9114 — "Claude Code hangs and freezes on startup in WSL 2 starting with v1.0.57"
  • #4077 — "Claude Code freeze in WSL"

Root Cause Analysis

1. System diagnostics ruled out common WSL2 issues:

| Check | Result |
|-------|--------|
| DNS resolution | 0.005s ✅ |
| API connectivity (curl) | 0.26s total ✅ |
| Memory/swap | 897/15909MB, 0 swap ✅ |
| I/O wait | 0% ✅ |
| CPU | 100% idle ✅ |

2. strace reveals repeated interop calls with 2.5-4.4s gaps:

sudo strace -p $(pgrep claude) -T -tt -e trace=network,read,write
17:08:30.838093 recvfrom(24, ...) = -1 EAGAIN           ← wait starts
                                                          ← ⏳ 2.7s blocked
17:08:33.558024 recvfrom(22, "C:\\Users\\<username>\r\n", ...)  ← Windows path received

Each cycle:

  1. socketpair() × 2 — pipes for child process
  2. recvfrom()EAGAIN — blocked 2-4s waiting for child
  3. recvfrom()"C:\\Users\\<username>" — Windows home path
  4. SIGCHLD — child process exits
  5. recvfrom()"/mnt/c/Users/<username>" — wslpath result
  6. read() → config data
  7. Repeat from step 1 (no caching)

3. strace -f -e trace=execve identifies the exact command:

[pid 9529] execve("/mnt/c/WINDOWS/System32/WindowsPowerShell/v1.0//powershell.exe",
    ["powershell.exe", "-Command", "$env:USERPROFILE"], ...) = 0

Timing:

17:11:21.756804  execve(powershell.exe)   ← start
17:11:24.272804  exited with 0            ← 2.5s later

4. This repeats 7+ times in 30 seconds with identical results:

| Gap start | Gap end | Duration | Result (always identical) |
|-----------|---------|----------|--------------------------|
| 30.838 | 33.558 | 2.7s | C:\Users\<username> |
| 34.530 | 36.959 | 2.4s | C:\Users\<username> |
| 37.992 | 40.685 | 2.7s | C:\Users\<username> |
| 41.710 | 44.245 | 2.5s | C:\Users\<username> |
| 45.266 | 48.141 | 2.9s | C:\Users\<username> |
| 49.159 | 53.598 | 4.4s | C:\Users\<username> |
| 54.642 | 57.265 | 2.6s | C:\Users\<username> |

7 calls × ~2.7s avg = ~19s of freeze in 30 seconds.

The Problem

  1. No caching — result is always identical but never cached
  2. PowerShell is the heaviest optioncmd.exe /c echo %USERPROFILE% is ~0.3s; environment variable reads are instant
  3. Repeats on every state transition — startup, exiting menus, termination all trigger fresh calls

Suggested Fix

The core issue is lack of caching, not the choice of PowerShell itself. The same immutable value is fetched 7+ times per session.

  1. Cache the result after the first callUSERPROFILE doesn't change during a session. Call once, store, reuse. This alone eliminates the problem regardless of how the value is fetched.
  2. Read from environment variables directly — WSL already exposes Windows environment info (e.g. WSLENV, /proc/*/environ), which would avoid interop entirely.
  3. If interop is required, use a lighter methodcmd.exe /c echo %USERPROFILE% (~0.3s) or wslvar USERPROFILE from wslu are significantly faster than PowerShell.
  4. If PowerShell must be used, add -NoProfile — profile loading accounts for most of the ~2.5s overhead. powershell.exe -NoProfile -Command "$env:USERPROFILE" would be much faster.

Current Workaround

A shell shim at ~/bin/powershell.exe that intercepts the $env:USERPROFILE query:

#!/bin/bash
for arg in "$@"; do
    if [[ "$arg" == '$env:USERPROFILE' ]]; then
        echo "C:\Users\"
        exit 0
    fi
done
exec /mnt/c/WINDOWS/System32/WindowsPowerShell/v1.0/powershell.exe "$@"

With export PATH="$HOME/bin:$PATH" in ~/.bashrc, this eliminates the freeze entirely.

What Should Happen?

Claude Code should resolve $env:USERPROFILE once and cache the result, or use a lighter-weight method (environment variable, cmd.exe). Startup, command transitions, and exit should complete without noticeable delay on WSL2.

Error Messages/Logs

Steps to Reproduce

  1. Install Claude Code natively on WSL2 (Ubuntu)
  2. Run claude
  3. Observe 20-40 second freeze during startup before TUI becomes responsive
  4. After TUI loads, run /plugin and press Esc to back out — ~2-3s freeze (single call)
  5. Run /exit — ~2-3s delay before terminating (single interop call)
  6. Verify with sudo strace -f -tt -T -e trace=execve -p $(pgrep claude) — repeated powershell.exe -Command "$env:USERPROFILE" calls visible during each freeze
Note: The severity of the freeze depends on each system's PowerShell cold start time. Our environment reports ~2.5s per call (profile loading alone: ~2492ms). Systems with lighter PowerShell profiles may experience shorter delays, but the unnecessary repeated calls remain inefficient regardless. You can check your PowerShell load time with: time powershell.exe -Command '$env:USERPROFILE'

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.50 (Claude Code)

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

WSL (Windows Subsystem for Linux)

Additional Information

  • Operating System: Windows 11 + WSL2 (Ubuntu 24.04)
  • CPU: Intel i5-13600KF
  • RAM: 16GB allocated to WSL2
  • Installation: Clean install, no plugins or extensions
  • PowerShell profile load time: ~2500ms (reported by PowerShell itself)
  • This affects all Claude Code WSL2 users — the interop overhead is inherent to WSL2's Hyper-V architecture
  • Severity scales with PowerShell profile complexity and Windows system load

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗