[BUG] LSP client sends constant document version on textDocument/didChange (never increments)

Resolved 💬 4 comments Opened Mar 4, 2026 by alliprice Closed Mar 7, 2026

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

  1. Enable an LSP plugin in Claude Code (e.g., typescript-language-server or pyright)
  2. Have Claude edit a file multiple times in one session
  3. Observe the textDocument/didChange notifications sent to the language server (via server-side logging or a proxy)
  4. Note that every notification carries the same version value

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)

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗