LSP plugin: typescript-language-server fails on Windows (ENOENT for .cmd shims)

Resolved 💬 4 comments Opened Apr 2, 2026 by neyer-more25 Closed Apr 6, 2026

Description

The TypeScript LSP plugin (typescript-lsp@claude-plugins-official) fails on Windows because npm install -g typescript-language-server creates .cmd shims, not real .exe binaries. Claude Code's LSP spawner uses Node.js spawn() (libuv uv_spawn) without shell: true, which cannot execute .cmd files on Windows.

Error

Error performing documentSymbol: ENOENT: no such file or directory, uv_spawn 'typescript-language-server'

Environment

  • Windows Server 2022 (10.0.20348)
  • Node.js v22.14.0
  • typescript-language-server 5.1.3 (globally installed via npm)
  • Claude Code CLI (native .exe)

Reproduction

// This fails (what Claude Code does):
const { spawn } = require('child_process');
spawn('typescript-language-server', ['--version']);
// → ENOENT

// This works:
spawn('typescript-language-server', ['--version'], { shell: true });
// → 5.1.3

The binary IS on PATH — which typescript-language-server finds it, and execSync (which uses a shell) works. Only shellless spawn fails because it can't resolve .cmd shims.

Suggested Fix

In the LSP process spawner, either:

  1. Add shell: true to spawn options on Windows
  2. Use cross-spawn which handles this transparently
  3. Detect Windows and append .cmd to the command name

This likely affects all LSP plugins on Windows, not just TypeScript.

Workaround Attempted

Compiled a C# .exe shim that delegates to cmd.exe /c typescript-language-server.cmd. The binary is found, but stdio handle inheritance through the shim doesn't work for LSP's bidirectional JSON-RPC protocol.

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗