[BUG] LSP clangd fails on Windows: "unresolvable URI" in textDocument/didOpen
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Disclaimer:
- The following was auto-generated by Claude-code
Environment
- Claude Code Version: 2.1.2
- OS: Windows 10/11 (MINGW64_NT-10.0-26200)
- LSP Plugin: clangd-lsp@claude-plugins-official v1.0.0
- clangd Version: 19.1.5 (from MinGW)
Summary
The clangd LSP plugin fails to register documents on Windows due to improper file URI formatting. Claude Code's LSP client sends Windows-style paths (C:\Users\...) to clangd without converting them to proper file URIs (file:///C:/Users/...), causing clangd to reject the textDocument/didOpen request.
Root Cause
The LSP client in Claude Code v2.1.2 doesn't properly convert Windows file paths to LSP-compliant file URIs before sending textDocument/didOpen notifications to language servers.
According to the LSP specification, the uri field must be a valid URI (RFC 3986), which for local files should be:
- Correct:
file:///C:/Users/username/project/src/main.cpp - Incorrect:
C:\Users\username\project\src\main.cpp
Impact
This bug affects all Windows users trying to use any LSP plugin (not just clangd). The issue likely affects:
- clangd-lsp (C/C++)
- pyright-lsp (Python)
- typescript-lsp (TypeScript)
- rust-analyzer-lsp (Rust)
- And all other LSP plugins on Windows
This explains why some users reported LSP working (likely on macOS/Linux) while others couldn't get it working (Windows users).
Related Issues
- #15168 - LSP plugin system not connecting to language servers
- #13952 - LSP servers not loading due to race condition (different issue, but related confusion)
- #14803 - LSP plugins not recognized
Proposed Fix
The LSP client needs to convert Windows file paths to proper file URIs before sending them to language servers. This conversion should:
- Replace backslashes with forward slashes:
C:\Users\...→C:/Users/... - Add the file URI scheme:
C:/Users/...→file:///C:/Users/... - Properly URL-encode any special characters in the path
Example TypeScript implementation:
function toFileUri(filePath: string): string {
if (process.platform === 'win32') {
// Convert backslashes to forward slashes
const normalizedPath = filePath.replace(/\\/g, '/');
// Add file:// scheme (triple slash for absolute paths)
return `file:///${normalizedPath}`;
}
// Unix-like systems
return `file://${filePath}`;
}
Configuration Details
Plugin is properly installed and enabled:
// ~/.claude/settings.json
{
"enabledPlugins": {
"clangd-lsp@claude-plugins-official": true
}
}
clangd initializes successfully:
2026-01-08T13:38:59.873Z [DEBUG] [LSP SERVER plugin:clangd-lsp:clangd] I[15:38:59.861] clangd version 19.1.5
2026-01-08T13:38:59.955Z [DEBUG] LSP server plugin:clangd-lsp:clangd initialized
The issue is purely in the URI formatting when sending textDocument/didOpen.
Workaround
None currently available. The bug is in Claude Code's LSP client, not in user configuration.
Downgrading to v2.0.67 (last known working LSP version) is not recommended as it has the race condition bug (#13952) that prevents LSP from loading at all.
Additional Notes
- The clangd binary works perfectly with LunarVim and VS Code on the same machine
- Indexes are being built correctly at
.cache/clangd/index/ - The
compile_commands.jsonexists and is valid - This is a Windows-specific bug in the LSP client implementation
What Should Happen?
Expected Behavior
- clangd receives properly formatted file URI:
file:///C:/Users/username/project/src/main.cpp textDocument/didOpensucceeds- Document is registered with clangd
- LSP operations (prepareCallHierarchy, goToDefinition, etc.) work correctly
Actual Behavior
- clangd receives improperly formatted URI
textDocument/didOpenfails with error:Failed to decode textDocument/didOpen request: unresolvable URI at (root).textDocument.uri- Document is NOT registered with clangd
- All subsequent LSP operations fail with:
trying to get AST for non-added document
Error Messages/Logs
## Debug Logs
From `~/.claude/debug/<session>.txt`:
2026-01-08T13:40:40.671Z [DEBUG] [LSP PROTOCOL plugin:clangd-lsp:clangd] Sending notification 'textDocument/didOpen'.
2026-01-08T13:40:40.671Z [DEBUG] LSP: Sent didOpen for C:\Users\username\project\src\main.cpp (languageId: cpp)
2026-01-08T13:40:40.672Z [DEBUG] [LSP PROTOCOL plugin:clangd-lsp:clangd] Sending request 'textDocument/prepareCallHierarchy - (1)'.
2026-01-08T13:40:40.672Z [DEBUG] [LSP SERVER plugin:clangd-lsp:clangd] I[15:40:40.673] <-- textDocument/didOpen
2026-01-08T13:40:40.673Z [DEBUG] [LSP SERVER plugin:clangd-lsp:clangd] E[15:40:40.674] Failed to decode textDocument/didOpen request: unresolvable URI at (root).textDocument.uri
2026-01-08T13:40:40.674Z [DEBUG] [LSP SERVER plugin:clangd-lsp:clangd] I[15:40:40.675] <-- textDocument/prepareCallHierarchy(1)
2026-01-08T13:40:40.675Z [DEBUG] [LSP SERVER plugin:clangd-lsp:clangd] I[15:40:40.675] --> reply:textDocument/prepareCallHierarchy(1) 0 ms, error: -32602: trying to get AST for non-added document
**Key line**: `LSP: Sent didOpen for C:\Users\username\project\src\main.cpp (languageId: cpp)`
This shows Claude Code is sending the Windows backslash path format directly, which violates the LSP specification requiring file URIs.
Steps to Reproduce
Steps to Reproduce
- Install clangd LSP plugin:
/plugin install clangd-lsp@claude-plugins-official - Ensure clangd is installed and in PATH (verify with
clangd --version) - Have a C++ project with
compile_commands.jsonin the project root - Open a C++ file in VS Code (or any editor)
- Use Claude Code's LSP tool:
LSPwith operationprepareCallHierarchyon any C++ file
Claude Model
Sonnet (default)
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.2
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
PowerShell
Additional Information
_No response_
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗