typescript-lsp plugin ENOENT on Windows: spawn without shell can't resolve .cmd shims
Summary
The typescript-lsp plugin fails on Windows with ENOENT: no such file or directory, uv_spawn 'typescript-language-server' despite the binary being correctly installed and on PATH.
Environment
- Claude Code: latest (desktop app, Windows)
- Windows 11 Pro 10.0.26200
- Node.js v24.14.0 (via nvm4w)
typescript-language-server5.1.3 installed globally (npm i -g typescript-language-server typescript)
Reproduction
- Windows machine, install
typescript-language-serverglobally - Verify it works:
typescript-language-server --version→5.1.3✓ - Enable
typescript-lsp@claude-plugins-officialplugin - Start a Claude Code session
plugin:typescript-lsp:typescript @ unknown (user)
ENOENT: no such file or directory, uv_spawn 'typescript-language-server'
Root Cause
On Windows, npm i -g creates .cmd shim files (batch wrappers):
C:\nvm4w\nodejs\typescript-language-server ← shell script (bash)
C:\nvm4w\nodejs\typescript-language-server.cmd ← Windows batch wrapper
C:\nvm4w\nodejs\typescript-language-server.ps1 ← PowerShell wrapper
child_process.spawn('typescript-language-server') without { shell: true } looks for an exact executable named typescript-language-server (or .exe). On Windows, it does NOT resolve .cmd shims. The spawn fails with ENOENT.
In bash (Git Bash/MINGW64), the shell script version works fine. But Node.js spawn bypasses the shell entirely.
Fix
Add { shell: true } when spawning language servers on Windows, or use cross-spawn logic to resolve .cmd extensions.
const opts = {};
if (process.platform === 'win32') opts.shell = true;
child_process.spawn('typescript-language-server', ['--stdio'], opts);
Workaround
Users can disable typescript-lsp plugin if they have Serena or another LSP provider.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗