[BUG] LSP client sends constant document version on textDocument/didChange (never increments)
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?
Claude Code's built-in LSP client always sends the same version number (typically 1) in textDocument/didChange notifications. Per the LSP specification, the version in VersionedTextDocumentIdentifier must be monotonically increasing after each change, including undos/redos:
The version number of a document will increase after each change, including undo/redo. The number doesn't need to be consecutive.
This is a spec compliance bug, not a feature request.
Why this matters: Many language servers use the document version to correlate diagnostic responses with the document state that produced them. When every didChange carries the same version, version-aware servers have no way to determine whether a diagnostic response corresponds to the current document state or a previous one. Servers that filter or discard stale diagnostics based on version comparison will malfunction.
Relationship to #17979: This is distinct from the stale diagnostics problem reported in #17979. That issue describes the symptom (stale diagnostics shown to the model after edits). This issue reports one root cause on the client side: the version field is never incremented, which breaks the protocol contract that servers rely on for ordering. Fixing this bug alone will not fully resolve #17979 (there are timing and invalidation concerns as well), but it is a necessary correctness fix regardless.
What Should Happen?
The LSP client should maintain a per-document version counter and increment it on every textDocument/didChange notification sent to the server. The version should start at 0 (or 1) on didOpen and increase by at least 1 on each subsequent didChange.
Steps to Reproduce
- Enable an LSP plugin in Claude Code (e.g.,
typescript-language-serverorpyright) - Have Claude edit a file multiple times in one session
- Observe the
textDocument/didChangenotifications sent to the language server (via server-side logging or a proxy) - Note that every notification carries the same
versionvalue
For example, with debug logging enabled on the server side, you will see something like:
didChange: file:///project/foo.ts version=1 (first edit)
didChange: file:///project/foo.ts version=1 (second edit)
didChange: file:///project/foo.ts version=1 (third edit)
All three carry version=1. The spec requires these to be monotonically increasing, e.g. 1, 2, 3.
Suggested Fix
Maintain a Map<string, number> (keyed by document URI) that tracks the current version for each open document. Initialize to 0 on textDocument/didOpen, increment before each textDocument/didChange, and remove the entry on textDocument/didClose. Use the current counter value as the version field in VersionedTextDocumentIdentifier.
This is a small, low-risk change.
Complementary Server-Side Work
Independently of this client bug, we have been working on server-side "eager diagnostic invalidation" patches for several language servers. These patches cause servers to immediately clear (invalidate) diagnostics for a file when they receive a didChange, before recomputation finishes. This addresses the stale diagnostics symptom from the server side and helps even with clients that do manage versions correctly, since there is always a window between "change sent" and "new diagnostics computed."
The server-side patches and this client-side fix are complementary and independent. The version bug should be fixed regardless of server-side behavior, because it violates the protocol specification.
Claude Model
Sonnet (default)
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗