TypeScript LSP plugin fails on Windows - spawn() doesn't handle npm wrapper scripts
Bug Description
The typescript-lsp plugin (and likely pyright-lsp and other npm-based LSP servers) fails to start on Windows with an ENOENT error.
Root Cause
When spawning LSP servers, Claude Code uses Node.js spawn() without the shell: true option. On Windows, this causes failures for npm-installed global packages because:
- npm creates wrapper scripts, not executables: When you run
npm install -g typescript-language-server, npm creates text-based wrapper scripts (.cmd,.ps1, shell scripts) in the global bin directory - not actual.exefiles.
- Windows kernel limitations: Unlike Unix (which understands shebangs), the Windows kernel can only directly execute
.exefiles. Whenspawn()asks Windows to runtypescript-language-server, Windows finds the shell script (no extension) and fails because it's not a valid Win32 executable.
- Shells handle this transparently: When you type the command in CMD/PowerShell, the shell automatically finds and executes the
.cmdwrapper. Butspawn()bypasses this.
Why .NET LSP tools work
Tools installed via dotnet tool install -g create actual .exe executables, which Windows can run directly. This is why csharp-ls works but typescript-language-server doesn't.
Reproduction Steps
- Install Claude Code on Windows
- Run
npm install -g typescript-language-server typescript - Enable the
typescript-lspplugin - Open a TypeScript project
- Observe LSP fails to initialize
Expected Behavior
LSP server should start successfully, as it does on macOS/Linux.
Suggested Fix
Option A: Use shell: true when spawning LSP servers on Windows:
spawn(command, args, { shell: process.platform === 'win32' });
Option B: Detect Windows and automatically wrap npm commands:
if (process.platform === 'win32' && !command.endsWith('.exe')) {
spawn('cmd.exe', ['/c', command, ...args]);
}
Workaround
Users can manually edit marketplace.json to change:
{
"command": "typescript-language-server",
"args": ["--stdio"]
}
To:
{
"command": "cmd.exe",
"args": ["/c", "typescript-language-server", "--stdio"]
}
However, this fix is overwritten on plugin updates.
Environment
- OS: Windows 10/11
- Claude Code: Latest
- Node.js: v20+
- npm: v10+
Additional Context
This affects any LSP server installed via npm globally, not just TypeScript. The same issue likely affects:
pyright-lsp(pyright)vscode-langservers-extracted(HTML, CSS, JSON LSPs)bash-language-server- Any other npm-based language server
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗