hermes - 💡(How to fix) Fix LSP spawn fails on Windows with WinError 193 for npm-installed language servers [1 pull requests]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

The LSP client fails to spawn any npm-installed language server (e.g., intelephense, typescript-language-server) on Windows with:

OSError: [WinError 193] %1 is not a valid Win32 application

Error Message

OSError: [WinError 193] %1 is not a valid Win32 application

Root Cause

When you npm install -g <package>, npm creates three files on Windows:

  • <bin> — a shell script (for MSYS/Git Bash)
  • <bin>.cmd — a batch file wrapper (for cmd.exe)
  • <bin>.ps1 — a PowerShell script (for PowerShell)

Python's shutil.which() resolves to the .cmd variant (via PATHEXT), but asyncio.create_subprocess_exec() passes it directly to Windows' CreateProcess() API. CreateProcess expects a valid PE executable — .cmd files are batch scripts that need cmd.exe /c to interpret them, so it fails with WinError 193.

Fix Action

Fixed

Code Example

OSError: [WinError 193] %1 is not a valid Win32 application

---

@staticmethod
def _win_wrap_cmd(cmd: list[str]) -> list[str]:
    """On Windows, wrap .cmd/.bat shims so CreateProcess can run them."""
    exe = cmd[0]
    if exe.lower().endswith((".cmd", ".bat")):
        return ["cmd.exe", "/c", *cmd]
    return cmd

---

cmd = self._command
if sys.platform == "win32":
    cmd = self._win_wrap_cmd(cmd)
RAW_BUFFERClick to expand / collapse

Description

The LSP client fails to spawn any npm-installed language server (e.g., intelephense, typescript-language-server) on Windows with:

OSError: [WinError 193] %1 is not a valid Win32 application

Root Cause

When you npm install -g <package>, npm creates three files on Windows:

  • <bin> — a shell script (for MSYS/Git Bash)
  • <bin>.cmd — a batch file wrapper (for cmd.exe)
  • <bin>.ps1 — a PowerShell script (for PowerShell)

Python's shutil.which() resolves to the .cmd variant (via PATHEXT), but asyncio.create_subprocess_exec() passes it directly to Windows' CreateProcess() API. CreateProcess expects a valid PE executable — .cmd files are batch scripts that need cmd.exe /c to interpret them, so it fails with WinError 193.

Why Linux/macOS Is Unaffected

On Linux and macOS, npm creates shell scripts with a shebang (#!/usr/bin/env node) and sets the execute permission bit. When create_subprocess_exec runs one, the OS kernel reads the shebang and routes it to the Node interpreter automatically. Windows has no shebang mechanism — it relies on file extensions and CreateProcess, which can only natively run PE executables (.exe). This is why the issue is Windows-specific.

Affected Servers

Any LSP server installed via npm, including:

  • intelephense (PHP)
  • typescript-language-server / tsserver (TypeScript/JavaScript)
  • vscode-langservers-extracted (HTML/CSS/JSON/ESLint)
  • svelte-language-server
  • Any other npm-installed LSP binary

Environment

  • OS: Windows 10 (Build 26200)
  • Python: 3.11.15
  • Node.js: v24.14.0
  • npm: 11.9.0
  • Hermes Agent: Windows native (not WSL)

Steps to Reproduce

  1. Install any npm-based LSP server: npm install -g intelephense
  2. Open a project that triggers that LSP (e.g., a PHP/Laravel project)
  3. LSP manager attempts to spawn the server
  4. asyncio.create_subprocess_exec fails with WinError 193

Proposed Fix

In agent/lsp/client.py, detect Windows .cmd/.bat shims and wrap them with cmd.exe /c before passing to create_subprocess_exec:

@staticmethod
def _win_wrap_cmd(cmd: list[str]) -> list[str]:
    """On Windows, wrap .cmd/.bat shims so CreateProcess can run them."""
    exe = cmd[0]
    if exe.lower().endswith((".cmd", ".bat")):
        return ["cmd.exe", "/c", *cmd]
    return cmd

Then in _spawn():

cmd = self._command
if sys.platform == "win32":
    cmd = self._win_wrap_cmd(cmd)

Minimal, backward-compatible fix — non-Windows platforms are unaffected, and native .exe binaries pass through untouched.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - 💡(How to fix) Fix LSP spawn fails on Windows with WinError 193 for npm-installed language servers [1 pull requests]