[LSP] Language servers on user PATH not found — "Command 'X' not found or is in an unsafe location (current directory)" (rust-analyzer + clangd, Windows)
Summary
The Claude Code LSP plugin host fails to launch any language server whose binary lives on the user PATH (rather than the machine/system PATH), erroring with:
Command 'rust-analyzer' not found or is in an unsafe location (current directory)
The identical failure happens with clangd. Both binaries are correctly installed, on the user's PATH, and run fine from a shell. LSP is therefore completely unusable for Rust and C/C++ on this setup.
Because rust-analyzer-lsp and clangd fail the same way, this is the shared LSP host / server-resolution logic, not a per-plugin bug.
Environment
- OS: Windows 11
- Claude Code: desktop app
- Plugins (
claude-plugins-official):rust-analyzer-lspv1.0.0,clangd rust-analyzer1.96.1 —%USERPROFILE%\.cargo\bin\rust-analyzer.exe(rustup proxy).rust-analyzer --versionworks in a shell.clangd—%LOCALAPPDATA%\Programs\clangd\22.1.6\bin\clangd.exe, on the user PATH.clangd --versionworks in a shell.
Reproduction
rustup component add rust-analyzer(proxy lands in~/.cargo/bin, which is on the user PATH).- Open a Rust project; invoke any LSP operation (e.g.
workspaceSymbol). - →
Command 'rust-analyzer' not found or is in an unsafe location (current directory). - Same on a C/C++ file →
Command 'clangd' not found or is in an unsafe location (current directory).
What was ruled out (extensively)
- Binary is fine:
rust-analyzer --version/clangd --versionboth run from a shell on the same machine/user. - Not the rustup symlink shim: replacing
~/.cargo/bin/rust-analyzer.exe(symlink →rustup.exe) with a real copy of the binary / a copy ofrustup.exe— no change. - Not editor-specific: identical failure in both VS Code and Zed.
- Not the PATH location: placing a working proxy in
%LOCALAPPDATA%\Microsoft\WindowsApps(user PATH) and inC:\Windows\System32(system PATH — on every process's PATH), followed by a full app restart, still fails identically. - Affects both plugins the same way → shared host, not per-plugin.
Likely cause
The LSP host process appears to run with a stripped environment that omits the user's PATH entries, and/or resolves the server binary once at host startup and caches the "not found" result (adding the binary to System32 afterward + restarting did not help). The "unsafe location (current directory)" guard may additionally be over-rejecting otherwise-valid resolutions.
Impact
Go-to-definition, find-references, diagnostics, and symbol search are entirely unavailable for Rust and C/C++, despite correctly-installed, PATH-available, working language servers. This is a poor first-run experience: users install exactly what the plugin READMEs instruct (rustup component add rust-analyzer, clangd on PATH), the binaries work everywhere else on the machine, yet the plugin never finds them — with no configuration knob to point it at the right path.
Suggested fixes
- Spawn the LSP host with the full user environment/PATH (not just the system PATH).
- Additionally probe common per-user install locations (
~/.cargo/bin,%LOCALAPPDATA%\Programs\..., Homebrew, etc.). - Provide an explicit
command/ server-binary-path override in plugin or user config. - Re-resolve the server per request instead of caching a startup "not found".
6 Comments
^ Do not open the above zip got the same comment in my issue from another account.
yea, immediately got that zip right when posted an issue. Kinda sus
Ran into the same error with
clangd-lspon Windows 10 (Claude Code 2.1.204, nativeclaude.exebuild) and dug into the resolution logic. Findings that may help narrow it down:PATH placement is irrelevant — confirmed. clangd 22.1.8 (winget
LLVM.LLVM) failed identically from three different directories: a standalone dir on PATH,C:\Program Files\LLVM\bin(front of user PATH,where.exe clangdresolves it), and even the plugin's own cachebindir. Fresh process each time, so it's not the cached negative result.The resolver's algorithm looks correct — the failure seems runtime-specific. From the bundled JS in
claude.exe(minified names from 2.1.204): commands containing a slash bypass resolution entirely (iSe); bare names go throughREn, which runs%SYSTEMROOT%\System32\where.exe <cmd>viaexecFileSyncwithenv: process.env, then filters each candidate:lstatSync(c, {throwIfNoEntry:false}) === undefined(X9a)process.cwd()(Umn) — notably, iffs.realpathSync.native()of the candidate's parent dir throws, the candidate is treated as unsafe.com,.exe,.bat,.cmd} (xom)I replicated this exact chain in Node 20 from the same environment and working directory:
where.exereturns the candidates and every filter passes. Yet insideclaude.exethe same inputs produceCommand 'clangd' not found or is in an unsafe location (current directory). So the suspect is a behavioral difference in the native build's runtime —execFileSyncofwhere.exe(options includetimeout+windowsHide) orrealpathSync.nativeare the candidates worth checking.Workaround that works today: an absolute path in the LSP server config skips the resolver (the slash check above). Since the official plugin hardcodes
"command": "clangd", this means either patching the marketplace cache entry (reverts on refresh) or a small local plugin whoselspServersuses the absolute path.Second, separate bug found while testing the workaround: if the configured
commandis an absolute path containing spaces (e.g.C:\Program Files\LLVM\bin\clangd.exe), the LSP tool silently fails to register — no error anywhere, the tool just doesn't exist in the session. The 8.3 short form (C:\PROGRA~1\LLVM\bin\clangd.exe) works and gives fully functional LSP (cross-TU findReferences/goToDefinition verified against a CMake/Qt project withcompile_commands.json). Happy to file that one separately if useful.The above comment was authored and posted by claude itself, sorry for the slop, guys. But it is correct if you care to read through it.
As a workaround we just ended up writing an override plugins\clangd-local-override\.claude-plugin\plugin.json with the full path without spaces and removing the official spec.
Btw, clangd-lsp does not handle .m/.mm files in windows... Had to add the extensions to my override.
@skoulik thanks, it really helped