Summary
A critical synchronization failure occurred between the Sublime Text LSP client and the OmniSharp Language Server. Specifically, after a file save operation, any attempt to trigger a Code Action resulted in the error: LSP: ignoring edit due to non-matching document version. This forced a manual “close and reopen” workflow, severely degrading the developer experience and breaking the Language Server Protocol (LSP) state machine.
Root Cause
The issue stems from a desynchronization of the document state between the local editor (Sublime Text) and the remote server (OmniSharp).
- Version Mismatch: The LSP protocol relies on an incremental
versionnumber for every change made to a buffer. - Implicit Save Side-Effects: When the user saves the file, the editor performs a disk write. In this specific configuration, the editor’s internal versioning incremented or reset in a way that the LSP Client failed to communicate the new version to the LSP Server.
- Optimistic Concurrency Control: OmniSharp uses the version number to ensure that a “Code Action” (which provides an edit) is applied to the exact same text state it was calculated for. Because the server perceived the client’s version as “stale” or “unknown” post-save, it rejected the edit to prevent data corruption or text mangling.
Why This Happens in Real Systems
In distributed systems and complex IDE integrations, this is a classic State Synchronization Problem.
- Race Conditions: A code action might be calculated based on Version 5, but by the time the “Apply Edit” command is sent, the editor has already saved and bumped the state to Version 6.
- Out-of-Band Updates: Many editors use asynchronous file saving. If the file system changes (via an external plugin or a background auto-save), the In-Memory Buffer and the LSP Server’s Virtual Document diverge.
- Protocol Implementation Gaps: Not all LSP clients implement the
textDocument/didSavenotification correctly, or they fail to reconcile the versioning increment required by the server after a physical disk write.
Real-World Impact
- Developer Velocity Loss: The “close and reopen” workaround is a high-friction task that breaks the developer’s “flow state.”
- Data Integrity Risks: If the protocol did not error out and instead applied the edit to the wrong version, it would result in misplaced code insertions, leading to syntax errors or, worse, silent logic bugs.
- Tooling Unreliability: When the primary language intelligence tool (OmniSharp) becomes inconsistent, developers lose trust in Automated Refactoring and Code Completion.
Example or Code
The logical failure can be represented by this sequence of events:
// 1. Client sends request based on Version 10
{
"method": "textDocument/codeAction",
"params": { "textDocument": { "uri": "file:///main.cs", "version": 10 } }
}
// 2. User saves file; Editor bumps version to 11 internally
// 3. User triggers Code Action
// 4. Client sends the edit (calculated for Version 10)
{
"method": "textDocument/applyEdit",
"params": { "textDocument": { "uri": "file:///main.cs", "version": 10 }, "edit": { ... } }
}
// 5. Server Rejects
// Response: "LSP: ignoring edit due to non-matching document version"
// Expected Version: 11 | Received Version: 10
How Senior Engineers Fix It
A senior engineer approaches this by looking at the Communication Contract rather than just restarting the app.
- Force Synchronization: Ensure the LSP client is configured to send a
textDocument/didChangenotification immediately following adidSaveevent to force the server to sync its internal buffer. - Version Reconciliation: Implement or adjust the client settings to ensure that the
versionproperty passed in theapplyEditcall is always the currentest version held by the editor buffer. - Buffer Management: In Sublime Text, this often involves adjusting the
LSP.sublime-settingsto ensure that “Save on Focus Lost” or “Auto-save” features are not creating asynchronous version drifts. - Protocol Compliance Check: Verify if the OmniSharp instance is expecting a specific versioning behavior (like
incrementalvsfullsync) and align the Sublime LSP client settings accordingly.
Why Juniors Miss It
- Symptom-Oriented Troubleshooting: Juniors tend to focus on the error message (
non-matching document version) by trying to “fix the version” rather than understanding why the versions diverged. - Workaround Reliance: Instead of analyzing the State Machine, a junior will accept the “close and reopen” workaround as “just how the plugin works.”
- Ignoring the Protocol: Juniors often treat the LSP as a “black box” and fail to realize that the error is a deliberate safety mechanism designed to prevent text corruption.