Type: Bug
Full disclosure: I found the bug and could reproduce. The diagnostics below are made by Claude Code.
Environment
- VS Code: 1.141.0 (arm64)
- Python extension: 2026.8.0 (regression; 2026.2.2026021801 is not affected)
- Python Environments extension: 1.38.0
- OS: macOS 26.7.1 (Apple Silicon)
- Python 3.13.16, pytest 9.1.1, local venv
Summary
Every pytest run started from the Test Explorer takes about 5 seconds longer than pytest itself. The test is marked as passed almost immediately, but the run stays in progress, and "Finished running tests!" only appears about 5 seconds later. During that time a new run can't start ("Test execution already in progress, not starting a new one.").
This happens even for a single trivial test: pytest reports 1 passed in 0.02s, the Python process exits after about 0.6 s, and the Test Explorer reports 5.6 s.
Steps to reproduce
- On macOS, open a folder that contains:
# test_trivial.py
def test_trivial() -> None:
assert True
- Enable pytest (
"python.testing.pytestEnabled": true).
- Run
test_trivial from the Test Explorer.
Expected: the run ends as soon as the pytest process exits (well under 1 s, as with 2026.2).
Actual: the run ends about 5 s after pytest exits. The duration in the Test Explorer is about 5 s plus the pytest time.
Analysis
In 2026.8.0, PytestTestExecutionAdapter.runTests ends with:
finally { await awaitDeferredWithTimeout(deferredTillServerClose, RESULT_PIPE_DRAIN_TIMEOUT_MS) } // 5e3
That deferred is resolved only by startRunResultNamedPipe, through the reader's onClose. In 2026.2 the deferred was also resolved when the cancellation token was cancelled (n.onCancellationRequested(() => s.dispose())), which runTestsNew triggers when the subprocess closes. 2026.8.0 removed that path, so the run now ends only when onClose fires.
On macOS onClose never fires. On non-Windows platforms createReaderPipe does mkfifo, open(O_RDONLY | O_NONBLOCK) and wraps the fd in new net.Socket({ fd }). When the writer (the vscode_pytest plugin) writes and its process exits, that socket receives the data but never emits end or close. The wait therefore always runs to the 5000 ms timeout.
Standalone reproduction of the reader's behaviour (Node 26 on macOS; I could not test VS Code's bundled Electron/Node directly):
// fifo_probe.mjs - usage: node fifo_probe.mjs /path/to/python
import { execFileSync, spawn } from "node:child_process";
import { promises as fsp, constants as C, rmSync } from "node:fs";
import net from "node:net";
const p = `${process.env.TMPDIR}/probe_fifo_${process.pid}`;
rmSync(p, { force: true });
execFileSync("mkfifo", [p]);
const t0 = Date.now();
const log = (m) => console.log(`[+${((Date.now() - t0) / 1000).toFixed(2)}s] ${m}`);
const fh = await fsp.open(p, C.O_RDONLY | C.O_NONBLOCK);
const s = new net.Socket({ fd: fh.fd });
for (const ev of ["data", "end", "close", "error"]) s.on(ev, () => log(`socket ${ev}`));
const writer = `import time\nf=open(${JSON.stringify(p)},"wb"); f.write(b"content-length: 2\\n\\n{}"); f.flush(); time.sleep(0.3)`;
spawn(process.argv[2], ["-c", writer], { stdio: "inherit" }).on("exit", () => log("writer exited"));
setTimeout(() => { log("gave up after 6s"); process.exit(0); }, 6000);
Output:
[+0.02s] socket data
[+0.33s] writer exited
[+6.00s] gave up after 6s
No end or close is emitted after the writer exits.
Suggested fix
Resolve the drain deferred once the subprocess has exited and the pipe has had a chance to flush (as 2026.2 did through the cancellation token). Alternatively, end the wait when the plugin's final message for the run arrives, rather than relying on EOF from a non-blocking FIFO socket, which doesn't arrive on macOS.
Workaround
Install Python extension 2026.2.x ("Install Specific Version...") and disable auto-update for it.
Extension version: 2026.8.0
VS Code version: Code 1.141.0 (Universal) (2a59476c9bfcb90b3ddc372c36762471b7dfad1c, 2026-10-06T10:15:52+02:00)
OS version: Darwin arm64 25.6.0
Modes:
- Python version (& distribution if applicable, e.g. Anaconda): 3.13.16
- Type of virtual environment used (e.g. conda, venv, virtualenv, etc.): Poetry
- Value of the
python.languageServer setting: Pylance
User Settings
venvPath: "<placeholder>"
languageServer: "Pylance"
testing
• pytestArgs: "<placeholder>"
• pytestEnabled: true
• autoTestDiscoverOnSavePattern: "<placeholder>"
terminal
• activateEnvironment: false
experiments
• enabled: false
Type: Bug
Full disclosure: I found the bug and could reproduce. The diagnostics below are made by Claude Code.
Environment
Summary
Every pytest run started from the Test Explorer takes about 5 seconds longer than pytest itself. The test is marked as passed almost immediately, but the run stays in progress, and "Finished running tests!" only appears about 5 seconds later. During that time a new run can't start ("Test execution already in progress, not starting a new one.").
This happens even for a single trivial test: pytest reports
1 passed in 0.02s, the Python process exits after about 0.6 s, and the Test Explorer reports 5.6 s.Steps to reproduce
"python.testing.pytestEnabled": true).test_trivialfrom the Test Explorer.Expected: the run ends as soon as the pytest process exits (well under 1 s, as with 2026.2).
Actual: the run ends about 5 s after pytest exits. The duration in the Test Explorer is about 5 s plus the pytest time.
Analysis
In 2026.8.0,
PytestTestExecutionAdapter.runTestsends with:That deferred is resolved only by
startRunResultNamedPipe, through the reader'sonClose. In 2026.2 the deferred was also resolved when the cancellation token was cancelled (n.onCancellationRequested(() => s.dispose())), whichrunTestsNewtriggers when the subprocess closes. 2026.8.0 removed that path, so the run now ends only whenonClosefires.On macOS
onClosenever fires. On non-Windows platformscreateReaderPipedoesmkfifo,open(O_RDONLY | O_NONBLOCK)and wraps the fd innew net.Socket({ fd }). When the writer (thevscode_pytestplugin) writes and its process exits, that socket receives the data but never emitsendorclose. The wait therefore always runs to the 5000 ms timeout.Standalone reproduction of the reader's behaviour (Node 26 on macOS; I could not test VS Code's bundled Electron/Node directly):
Output:
No
endorcloseis emitted after the writer exits.Suggested fix
Resolve the drain deferred once the subprocess has exited and the pipe has had a chance to flush (as 2026.2 did through the cancellation token). Alternatively, end the wait when the plugin's final message for the run arrives, rather than relying on EOF from a non-blocking FIFO socket, which doesn't arrive on macOS.
Workaround
Install Python extension 2026.2.x ("Install Specific Version...") and disable auto-update for it.
Extension version: 2026.8.0
VS Code version: Code 1.141.0 (Universal) (2a59476c9bfcb90b3ddc372c36762471b7dfad1c, 2026-10-06T10:15:52+02:00)
OS version: Darwin arm64 25.6.0
Modes:
python.languageServersetting: PylanceUser Settings