Skip to content

pyright on Windows: spawn fails with ENOENT: uv_spawn 'pyright-langserver' — needs .cmd extension #72

@MohamedFarht

Description

@MohamedFarht

Summary

On Windows, every LSP request through the pyright plugin fails immediately with:

Error performing documentSymbol: ENOENT: no such file or directory, uv_spawn 'pyright-langserver'

The LSP MCP server eventually disconnects after repeated failures. The plugin appears installed and enabled (claude plugin list shows pyright@claude-code-lsps Status: ✔ enabled), so the failure is silent from the user's perspective unless they specifically inspect tool errors.

Root cause

pyright/.lsp.json at HEAD specifies:

{
    "python": {
        "command": "pyright-langserver",
        "args": ["--stdio"],
        ...
    }
}

The harness spawns this through libuv's uv_spawn, which on Windows resolves PATH against PATHEXT looking for .exe (and a few others) but does not auto-resolve .cmd / .bat / .ps1 shims — a long-standing libuv/Node behavior shared by child_process.spawn(cmd, args, { shell: false }).

The npm pyright package on Windows installs only:

  • pyright-langserver.cmd
  • pyright-langserver.ps1
  • pyright-langserver (bash shim, unused on native Windows)

There is no pyright-langserver.exe, so the bare command name never matches. Same root cause likely affects every Node-based language server in this repo on Windows.

Repro

  1. Windows 10/11 with Node.js installed via the official MSI (puts C:\Program Files\nodejs on PATH).
  2. npm i -g pyright — verify where pyright-langserver returns the .cmd shim.
  3. Install this plugin: claude plugin install pyright@claude-code-lsps.
  4. Open any .py file and trigger an LSP call (e.g. documentSymbol).
  5. Observe ENOENT: uv_spawn 'pyright-langserver'.

Suggested fix

Make the command field platform-aware. Either:

Option A — runtime resolution in the harness shim (preferred, fixes every Node-based plugin in one place): when process.platform === 'win32' and the resolved binary is a .cmd / .bat, spawn with shell: true or via cmd.exe /c.

Option B — patch each plugin's .lsp.json: ship per-platform command, e.g.

{
    "python": {
        "command": {
            "win32": "pyright-langserver.cmd",
            "default": "pyright-langserver"
        },
        "args": ["--stdio"],
        ...
    }
}

(Schema change — only viable if the LSP loader supports it.)

Option C — minimum patch (won't help non-Node plugins): hardcode .cmd in pyright/.lsp.json. One-line diff:

-        "command": "pyright-langserver",
+        "command": "pyright-langserver.cmd",

This breaks macOS/Linux, so Option A or B is the real fix; Option C only buys time.

Workaround for users today

Edit the cached file directly:

~/.claude/plugins/cache/claude-code-lsps/pyright/<version>/.lsp.json

and append .cmd to command. Restart Claude Code. The patch is wiped each time the plugin updates.

Likely affected siblings

Every Node-based language server in this repo: vtsls, vscode-langservers, eslint, pyright, etc. Worth grepping command: fields across all .lsp.json files.

Environment

  • Windows 10 Pro 22H2 (build 19045)
  • Node.js installed at C:\Program Files\nodejs
  • Claude Code (claude plugin list reports plugin pyright@claude-code-lsps v0.1.0)
  • pyright installed globally via npm

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions