[BUG] Startup blocks on working-tree stat — first response delayed minutes on WSL2 /mnt/ with medium/large repos

Resolved 💬 2 comments Opened Apr 24, 2026 by isecream9 Closed Jun 1, 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?

Summary

Claude Code's first user turn is blocked on git status / working-tree stat() during session startup. On WSL2 /mnt/* mounts — where every per-file stat crosses the Linux↔Windows 9p/drvfs boundary at millisecond cost — this scales linearly with working-tree size and makes medium/large repos effectively unusable.

The first response time tracks git status latency almost 1:1 in the same cwd.

The failure mode is silent: the TUI just shows a spinner ("Booping…", "Tempering…", etc.) with no progress indicator, no warning, no error. Users have no way to tell that git is the bottleneck.

Measured Data

Same machine, same WSL2 distro, same Claude Code version, same auth. Only the cwd changes.

| Repo | Tracked files (git ls-files) | time git status (real / user / sys) | First claude response to "who are you" |
|---|---|---|---|
| /mnt/e/.../repo-a | 3,243 | 28.6s / 0.6s / 1.9s | ~22s |
| /mnt/e/.../repo-b branch A | 21,650 | 144s / 2.0s / 15.5s | ~2–3 min |
| /mnt/e/.../repo-b branch B | ~70,000 | not measured | ~7 min |

Key observations:

  • git ls-files (index-only) is consistently ~30–60 ms on all repos above — the git index itself is healthy.
  • In time git status, user CPU time is tiny (0.6–2.0 s) while real time is 28–144 s — the time is spent waiting on stat() syscalls, not in git or Claude Code CPU logic.
  • Same hang reproduces with claude -p "<prompt>" (non-interactive), so this is not a TUI rendering problem.

Debug Log Excerpts

From claude -d --verbose in repo-b during a 2 min 8 s+ hang on the first "who are you":

2026-04-22T10:02:36.042Z [DEBUG] [FileIndex] getProjectFiles called, respectGitignore=true
2026-04-22T10:02:36.042Z [DEBUG] [FileIndex] getFilesUsingGit called
2026-04-22T10:02:37.206Z [DEBUG] [FileIndex] git ls-files (tracked) took 1164ms
2026-04-22T10:02:37.226Z [DEBUG] [FileIndex] git ls-files: 63278 tracked files in 1184ms
2026-04-22T10:02:37.609Z [DEBUG] [FileIndex] cache refresh completed in 1568ms
2026-04-22T10:02:39.470Z [DEBUG] [FileIndex] background untracked fetch: 0 files

After [FileIndex] finishes, the log shows only repeated Fast mode unavailable: Fast mode requires extra usage billing entries for ~2 minutes before the first assistant API response begins streaming. Critically, the stat()-bound work that actually consumes those 2 minutes is not logged with per-call timing — it is silent from the user's perspective.

Ruled-Out Causes

  • Not #14352 (USERPROFILE / powershell.exe interop): no [SLOW OPERATION DETECTED] ... powershell.exe lines appeared in the debug log.
  • Not MCP: reproduces with claude --strict-mcp-config --mcp-config /dev/null. MCP server init times are visible in the log (~2–20 s total) and complete well before the hang.
  • Not ~/.claude.json corruption: reproduces after deleting the project entry with jq 'del(.projects["..."])'.
  • Not CLAUDE.md: log shows No CLAUDE.md/rules files found.
  • Not terminal/TUI rendering: reproduces in non-interactive -p mode.
  • Not non-ASCII path characters: reporter's actual path contained non-ASCII characters, but isolation testing ruled this out as a factor — the correlation is with file count, not path encoding.
  • Not file count per se: git ls-files (which Claude Code already uses for the file index) is millisecond-fast even at 63k files. The cost is specifically working-tree stat().

What Should Happen?

Startup should not block the first user turn on working-tree stat() operations. Possible fixes, in order of impact:

  1. Async the stat path. Gate the first API request only on git ls-files (index read, always fast). Defer git status / untracked enumeration / working-tree stat to a background task and surface results when ready.
  2. Hard timeout with graceful degradation. If working-tree stat exceeds e.g. 3 s, abandon it for the first turn, fall back to the index snapshot, and log a warning.
  3. Detect and warn. At startup, if cwd is under /mnt/<letter>/ AND the working tree is nontrivial, emit a one-time actionable warning: "Repository is on a Windows-mounted filesystem; startup may be slow. For best performance move the repo under your Linux home directory or enable git config core.fsmonitor true."
  4. Log the stat phase. Whatever the fix, the debug log should include timing for the stat/git status step just as it currently does for git ls-files, so users can self-diagnose.

Error Messages/Logs

Steps to Reproduce

  1. WSL2 Ubuntu with Claude Code 2.1.117 or 2.1.119 installed natively.
  2. Clone or place a git repo on a /mnt/<letter>/ path with at least a few thousand tracked files.
  3. cd into the repo.
  4. time git status — note elapsed time T_git.
  5. time claude -p "who are you" — note elapsed time T_claude.
  6. Observe T_claude ≈ T_git + small overhead.

The correlation is tight enough that git status timing alone predicts first-response time.

Claude Model

Sonnet (default)

Is this a regression?

Yes, this worked in a previous version

Last Working Version

_No response_

Claude Code Version

2.1.117 (also reproduced on 2.1.119)

Platform

Anthropic API

Operating System

Ubuntu/Debian Linux

Terminal/Shell

WSL (Windows Subsystem for Linux)

Additional Information

Why This Matters

  • Many WSL2 users keep code on the Windows drive by necessity (shared with Windows IDEs, git clients, file sync, backup, etc.) and cannot simply move repos to ~/.
  • Because the failure is silent and scales with repo size, users can't easily distinguish this from other WSL2 hangs (#14352, #21692, #22855) and waste hours debugging the wrong things.
  • A single architectural fix (async the stat path) covers all repo sizes on all slow filesystems, not just WSL2.

Workarounds Tried

| Workaround | Result |
|---|---|
| --strict-mcp-config --mcp-config /dev/null | No change (MCP is not the bottleneck) |
| Delete project entry from ~/.claude.json | No change |
| Remove all .claude/ and CLAUDE.md | No change |
| git config core.fsmonitor true + core.untrackedcache true | Partial improvement, still seconds-to-minutes on /mnt/ |
| Move repo to WSL2 native filesystem (~/) | Not tested by reporter — but per WSL2 docs this is the standard fix and would confirm root cause |

Environment Details

  • OS: Windows 11 + WSL2 (Ubuntu)
  • Repo filesystem: NTFS via WSL2 9p/drvfs (/mnt/e/)
  • Node: v24.3.0 (bundled with Claude Code native install)
  • Auth: isecream9

View original on GitHub ↗

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