LSP server discovery fails on NixOS (assumes FHS-compliant paths)
Summary
LSP functionality is completely non-functional on NixOS despite LSP servers being properly installed and available in $PATH. Debug logs show that Claude Code's LSP manager initializes successfully but discovers zero servers, suggesting it assumes FHS-compliant paths like /usr/bin/ instead of using $PATH for discovery.
Environment
- OS: NixOS (non-FHS filesystem hierarchy)
- Claude Code Version: 2.0.76
-
LSP Servers Installed:
nil(Nix),pyright(Python), both verified in$PATH - Shell: Fish with proper PATH configuration
Steps to Reproduce
- Install Claude Code on NixOS
- Install LSP servers via Nix package manager:
# Example from home-manager configuration home.packages = [ pkgs.nil # Nix LSP server pkgs.pyright # Python LSP server ]; - Verify LSP servers are in PATH:
$ which nil /home/user/.nix-profile/bin/nil $ which pyright /home/user/.nix-profile/bin/pyright - Attempt to use LSP tool in Claude Code:
LSP operation: hover File: test.nix Result: "No LSP server available for file type: .nix"
Expected Behavior
- Claude Code should discover LSP servers from
$PATH - LSP operations should work with
nilfor.nixfiles - LSP operations should work with
pyrightfor.pyfiles
Actual Behavior
- Zero LSP servers discovered despite being in PATH
- All LSP operations fail with "No LSP server available for file type"
- Debug logs confirm LSP manager initializes but finds no servers
Debug Log Evidence
From ~/.claude/debug/latest:
2026-01-02T16:37:40.895Z [DEBUG] LSP server manager initialized successfully
2026-01-02T16:37:40.896Z [DEBUG] LSP notification handlers registered successfully for all 0 server(s)
Later when attempting LSP operations:
2026-01-02T16:44:52.145Z [DEBUG] No LSP server available for file type .nix for operation hover
2026-01-02T16:45:10.460Z [DEBUG] No LSP server available for file type .py for operation hover
Key observation: registered successfully for all 0 server(s) - no servers discovered during initialization.
Root Cause Analysis
NixOS vs FHS Path Structure
NixOS (non-FHS):
- LSP servers:
/nix/store/<hash>-nil-<version>/bin/nil - Symlinked to:
~/.nix-profile/bin/nil - Available in
$PATH: ✅
Traditional Unix/FHS:
- LSP servers:
/usr/bin/pyrightor/usr/local/bin/nil - Available in
$PATH: ✅
Hypothesis
Claude Code's LSP discovery appears to be hardcoded to check FHS-standard locations rather than using $PATH for server discovery. This breaks on NixOS where binaries live in /nix/store/ paths.
Verification
The issue affects all LSP servers on NixOS:
-
nilfor Nix files: ❌ -
pyrightfor Python files: ❌ - Likely affects any LSP server on NixOS: ❌
Suggested Fix
LSP server discovery should:
-
Use
$PATHfor discovery instead of hardcoded paths -
Support checking via
which <server-name>to find actual executable location -
Allow manual LSP server configuration in settings.json as fallback:
{ "lsp": { "servers": { "nil": { "command": "/home/user/.nix-profile/bin/nil", "fileTypes": ["nix"] } } } }
Impact
- All NixOS users cannot use LSP functionality (a "game changer" feature per release announcement)
- This likely affects other non-FHS systems (Guix, etc.)
- LSP tool exists but is completely non-functional for this user base
Additional Context
- Discovered through actual usage session - user is daily Claude Code user who has never seen LSP invoked successfully
- Other tools (
nil,pyright) work perfectly when invoked directly via command line - Claude Code itself runs fine on NixOS - only LSP discovery is broken
Related: This is likely a cross-platform compatibility issue where development/testing on macOS/Ubuntu (FHS-compliant) didn't catch NixOS edge cases.
Please allow for .lsp.json files outside of Claude plugins. I manage all my Claude config with nix and I can't get LSPs to work
I have not had any issues with this myself, I used nix devshells... for example for nix LSP, I am using nixd over nil because nixd triggers passively on errors. Weirdly the few I have installed from the marketplace seem to work fine too.
In my project i just drop .lsp.json
{
"nix": {
"command": "nixd",
"args": [],
"extensionToLanguage": {
".nix": "nix"
}
}
}
and run:
claude --plugin-dir .
The problem with --plugin-dir IIRC is that it now treats the current directory as a plugin as opposed to a normal dir. And e.g. hot-reloading of other files like /skills stops working. There's not reason why .lsp.json doesn't work just like .mcp.json. I don't see why it has to be shipped as a plugin. it's a weird restriction