Skip to content

[Bug] Language servers installed with npm are reported as available but never start on Windows #1690

Description

@addyCooks

Description

On Windows, npm installs language servers (typescript-language-server, pyright, vscode-*-language-server) as .cmd shims. Nanocoder finds them with where (which understands .cmd) and reports them as available. But it then checks and starts them with execFileSync and spawn without a shell, and those cannot run a .cmd file. So no server starts and LSP features stay off. Only servers that ship as real .exe files (like gopls, rust-analyzer, clangd) should work.

Environment

  • OS: Windows 11 (10.0.26300)
  • Node version: 22.22.3
  • Nanocoder version: 1.31.0 (main at 6eaff7a)
  • typescript-language-server: 6.0.2, installed with npm install typescript-language-server typescript
  • Provider / Model: not relevant

Steps to Reproduce

  1. On Windows, run npm install typescript-language-server typescript and put node_modules\.bin on PATH.
  2. Make a project with tsconfig.json and a.ts.
  3. In that folder, call getKnownServersStatus() and discoverLanguageServers() from source/lsp/server-discovery.ts.
  4. Compare with cmd /c typescript-language-server --version and with spawn('typescript-language-server', ['--stdio']).

Expected Behavior

The server is discovered and started, like it is on Linux and macOS.

Actual Behavior

where typescript-language-server        -> node_modules/.bin/typescript-language-server  |  .../typescript-language-server.cmd
cmd /c typescript-language-server --version      -> 6.0.2      (Windows can run it)
execFileSync('typescript-language-server', ...)  -> FAILS: ENOENT

getKnownServersStatus() ...  {"name":"typescript-language-server","available":true}
discoverLanguageServers()    []
spawn('typescript-language-server', ['--stdio'])  -> error event: ENOENT

Suggested Fix

  • source/lsp/server-discovery.ts: findCommand (about lines 249-266) uses where, so it succeeds. verifyServer (about lines 274-290, execFileSync) and verifyLSPServerWithCommunication (about line 302, spawn) cannot run the shim. source/lsp/lsp-client.ts:69 has the same spawn.
  • Use cross-spawn for all three. I checked that cross-spawn.sync('typescript-language-server', ['--version']) returns 6.0.2 here. Note that cross-spawn is only a transitive dependency today and is not imported anywhere in the repo, so add it to package.json (and keep knip happy).
  • Or resolve <name>.cmd and run it through cmd.exe /d /s /c on win32. The node_modules/.bin fallback in findCommand finds the extensionless POSIX shim, which also can't be spawned on Windows.
  • Add a Windows-only test: put a fake typescript-language-server.cmd on PATH and expect discoverLanguageServers() to return it. That exact test fails today.

Additional Context

Activity

  1. added theissue type on Oct 9, 2026
  2. Srinidhi444 commented on Oct 10, 2026

    @Srinidhi444

    hey @addyCooks can i get assigned for this issue?

  3. addyCooks commented on Oct 10, 2026

    @addyCooks
    CollaboratorAuthor

    Assigned to you, @Srinidhi444!
    Quick heads-up for next time: please include a brief implementation plan when requesting an issue assignment
    It helps us understand your approach beforehand : )

  4. Srinidhi444 commented on Oct 10, 2026

    @Srinidhi444

    7. Assigned to you, @Srinidhi444!
    Quick heads-up for next time: please include a brief implementation plan when requesting an issue assignment
    It helps us understand your approach beforehand : )

    sure will keep that in mind

  5. Srinidhi444 commented on Oct 10, 2026

    @Srinidhi444

    Hey @addyCooks, I’ve implemented a fix locally using the cross-spawn approach suggested in the issue.

    The changes:

    • Add cross-spawn as a direct dependency and use it for version verification, discovery’s spawn check, and actual LSP startup.
    • Update the local node_modules/.bin fallback to select .exe, .cmd, or .bat files on Windows.
    • Pass the resolved command path and arguments separately so paths containing spaces work correctly.
    • Check synchronous launch errors and exit status so failed version checks aren’t accepted.

    I’ve also added six Windows regression tests covering discovery, local shims, paths with spaces, failed verification, and LSP initialization/shutdown. All six tests, type checks, and formatting checks pass locally.

    The implementation and targeted tests are ready. Does this approach sound good? If so, I’ll finish the full repository checks, add the patch changeset, and open a PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:lspLanguage server integrationbugSomething isn't workinggood first issueGood for newcomers

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions