microsoft / microsoft/vscode-python-environments
`pet server` `configure` hangs in a filesystem-scan busy-loop on large workspaces → 30s timeout × 3 retries = ~90s 100% CPU (thermal shutdown on laptops)
@DonJayamanne is already working on this.
Since Aug 31, 2026.
- Dominant language
- TypeScript
- Stars
- 138
- Forks
- 62
- Avg merge
- 1d 4h
- Merged PRs (30d)
- 35
Description
## Summary
The `pet` binary (`python-env-tools`, shipped by `ms-python.vscode-python-envs`) busy-loops inside a filesystem `stat`/`close` scan when handling a `configure` JSON-RPC request whose `environmentDirectories` glob is evaluated against a large workspace. The scan does not complete within the extension's 30-second `configure` timeout, so the extension kills `pet` (SIGTERM), restarts it, and re-sends `configure` — which hangs again. After 3 attempts (~90 s of sustained 100% CPU on one core) the extension gives up.
On a thermally-constrained laptop this ~90 s 100% CPU spike pushes the package past 105 °C and the embedded controller cuts power with **no OS-level log** (no OOM, no panic, no thermal trip in journald — the journal just ends mid-normal-activity). The bug therefore masquerades as a hardware/BIOS issue and is very hard to diagnose. Worth fixing for that reason alone, not just the wasted CPU.
## Environment
- Extension: `ms-python.vscode-python-envs` **v1.20.1** — the latest version compatible with my VS Code. (I have 1.22.0–1.36.0 installed too, but VS Code refuses to load them: *"Extension is not compatible with Code 1.108.1. Extension requires: ^1.110.0-20260204"*. So I can't test newer versions without also upgrading VS Code. Happy to re-test on 1.36.0 if a maintainer confirms whether the scan/timeout behavior changed.)
- VS Code: `1.108.1`
- OS: Ubuntu 24.04.3 LTS, kernel `6.17.0-22-generic`, x86_64
- `pet` binary: ELF 64-bit, static-pie, **with debug_info, not stripped**
- Hardware: HP OMEN laptop, Intel Core Ultra (Arrow Lake-H) + NVIDIA RTX 5070 Laptop (degraded cooling — needs repaste)
## The trigger workspace
The crash only happens for one of my open workspaces. Its size is the key:
```
$ find /home//workspace/large-project | wc -l
279488
$ du -sh /home//workspace/large-project
101G
```
**279,488 files / 101 GB**, including several `node_modules` trees with symlinks. The other workspaces I have open (346 / ~small files) configure in <1 s and never spin. The `configure` params the extension sends for this workspace:
```json
{"workspaceDirectories":["/home//workspace/large-project"],
"environmentDirectories":["/home//workspace/large-project/**/.venv"],
"pipenvExecutable":"pipenv","poetryExecutable":"poetry",
"cacheDirectory":".../pythonLocator"}
```
Note the `**/.venv` glob — pet walks the entire 279k-file tree looking for `.venv` dirs.
## Reproduction (CLI, deterministic, ~12 s)
`pet server` reads JSON-RPC over stdio with `Content-Length` framing. Sending the exact `configure` request the extension sends hangs pet in a `stat`/`close` scan loop:
```bash
$ # request body in configure.json (the JSON above)
$ ( printf "Content-Length: %s\n\n" "$(wc -c < configure.json)"; cat configure.json; sleep 13 ) \
| timeout -s INT 12 strace -c -f -e trace=futex,poll,ppoll,read,write,stat,newfstatat,openat,close \
~/.vscode/extensions/ms-python.vscode-python-envs-1.20.1-linux-x64/python-env-tools/bin/pet server
# exit code 124 (pet never responded within 12 s)
```
strace summary (12 s, no `pet find`, just `configure`):
```
% time seconds usecs/call calls errors syscall
72.50 0.203708 1 138906 close
27.50 0.077264 11 6792 4317 stat
0.00 0.000000 0 1 read
0.00 0.000000 0 1 poll
100.00 0.280972 1 145700 4317 total
```
So pet is in a tight `stat`/`close` loop walking the workspace, 64% of `stat`s returning ENOENT (probing for `.venv`/`python`/etc. at every entry). 12 s wasn't enough to finish; the extension's 30 s timeout isn't either.
## Extension log (from the actual crash session)
`~/.config/Code/logs/20260829T164624/window2/exthost/ms-python.vscode-python-envs/Python Environments.log`:
```
16:47:32.185 [info] [pet] Starting Python Locator .../pet server
16:47:32.186 [info] [pet] configure: Sending configuration update: {"workspaceDirectories":[".../"],"environmentDirectories":["...//**/.venv"],...}
16:48:02.186 [warning] [pet] Configure request timed out, killing hung process for restart
16:48:02.186 [error] [pet] configure: Configuration error Request 'configure' timed out after 30000ms
16:48:02.187 [warning] [pet] Restarting Python Environment Tools (attempt 3/3, waiting 4000ms)
16:48:02.188 [error] [pet] Python Environment Tools exited unexpectedly with code null, signal SIGTERM
16:48:06.195 [info] [pet] Starting Python Locator .../pet server # restart, send configure again
16:48:36.197 [warning] [pet] Configure request timed out, killing hung process for restart # 30s later, again
16:48:36.197 [error] PET failed after 3 restart attempts.
16:48:36.199 [warning] [priorityChain] .../ defaultInterpreterPath '/bin/python3' unresolvable, falling back to auto-discovery
```
Same pattern reproduces every time this workspace is opened (also seen in the `20260829T213146` session). Other workspaces configure in <1 s.
## Impact / why this matters
- **Wasted CPU + battery** on any machine: ~90 s of one pinned core per workspace open.
- **Silent hard power-off on thermally-constrained laptops**: I confirmed the causal link — killing the spinning `pet` dropped CPU package temp from 100 °C → 90 °C in 2 s. The ~90 s spike pushes the package past 105 °C and the EC cuts power with no OS log. I had repeated unexplained "auto-shutdowns" for weeks before tracing them here.
- The empty "Extension causes high cpu load" auto-issues (#1074, #1379, #1469, #1709) are very likely this same bug, never diagnosed because the reporters never attached a profile.
## Secondary issue: pet busy-loops on malformed input too
While figuring out the framing I sent a request without a valid `Content-Length` header. Instead of failing gracefully, `pet` entered an infinite error-spam loop writing the same error to stderr — **941,762 `write` calls in 12 s** (~78k writes/s), 100% CPU:
```
% time calls syscall
58% 941762 write
24% 98908 open
11% 188354 read
...
```
stderr was the error message recursively nesting itself. A malformed request should error once and continue, not spin. Likely the same lack of backoff/bounding that causes the `configure` hang.
## What I'd suggest (and can help validate)
1. **Bound the `configure` scan**: skip / prune common heavy dirs (`node_modules`, `.git`, `__pycache__`, `.venv` contents), cap depth or entry count, or make discovery incremental/lazy instead of a full synchronous walk that must finish before `configure` responds.
2. **Don't retry 3× with no backoff**: a workspace that times out once will time out 3 times — that's 90 s of guaranteed 100% CPU. Exponential backoff or a single retry would cut the blast radius.
3. **Fix the error-spam loop** on malformed input (fail once, don't busy-write).
4. If a maintainer can tell me which `pet` subcommand/request path is the right one to exercise, I can attach a `perf record` call graph (I have `perf` + the binary's debug symbols ready, just need to temporarily relax `perf_event_paranoid`). The strace above already localizes it to the env-discovery glob scan, but a flamegraph would pin the exact function.
## Workaround
Disable / uninstall the `ms-python.vscode-python-envs` extension, or avoid opening the large workspace, or narrow `python.envs.environmentDirectories` so the glob doesn't span the whole tree.
## Related
- #1709 (open), #1469, #1379, #1074 (closed) — empty "Extension causes high cpu load" auto-reports, likely this.
- #1289 / #1290 (v1.22.0) — related but different: that's unresolved `${workspaceFolder}` causing a *clean* ENOENT failure; this is a *hang/spin* on a valid (but large) workspace.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.