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)

Abierto
#1,747 0 comentarios 0 reacciones 1 asignado Ver en GitHub

@DonJayamanne ya está trabajando en esto.

Desde el 31/8/2026.

area-environment bug
Lenguaje dominante
TypeScript
Estrellas
138
Forks
62
Merge medio
1 d 4 h
PR fusionados (30 d)
35

Descripción

## 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.

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.