Windows: LSP servers fail with ENOENT because spawn doesn't resolve .cmd files
Description
On Windows, LSP server plugins (e.g. typescript-lsp, php-lsp, kotlin-lsp) fail with:
Error performing documentSymbol: ENOENT: no such file or directory, uv_spawn 'typescript-language-server'
Root Cause
npm global packages on Windows are installed as .cmd wrapper files (e.g. typescript-language-server.cmd). Node.js child_process.spawn without shell: true does not resolve .cmd files — it looks for an exact executable match.
The marketplace.json defines LSP commands without the .cmd extension:
{
"typescript": {
"command": "typescript-language-server",
"args": ["--stdio"]
}
}
Steps to Reproduce
- Install Claude Code on Windows
- Enable
typescript-lspplugin - Install
typescript-language-serverglobally:npm install -g typescript-language-server typescript - Try any LSP operation on a
.tsfile - Get
ENOENT: no such file or directory, uv_spawn 'typescript-language-server'
Expected Behavior
LSP servers should start successfully on Windows, just as they do on macOS/Linux.
Suggested Fix
When spawning LSP server processes on Windows, either:
- Use
shell: trueoption inchild_process.spawn - Use the
cross-spawnpackage - Automatically append
.cmdto commands onwin32platform
This is a well-known Node.js issue: https://nodejs.org/api/child_process.html#spawning-bat-and-cmd-files-on-windows
Workaround
Manually edit marketplace.json to append .cmd to LSP command values, or use a SessionStart hook to patch it automatically. Note that marketplace.json gets overwritten on plugin updates, so manual edits don't persist.
Environment
- OS: Windows 11
- Claude Code: latest stable
- Affected plugins: all LSP plugins (
typescript-lsp,php-lsp,kotlin-lsp, and others)
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗