Skip to content

noisy -32801 ("Content Modified") errors #3420

Description

@justinmk

How are you using the lua-language-server?

NeoVim

Which OS are you using?

MacOS

What is the issue affecting?

Other

Expected Behaviour

In the request-completion path, when the server has computed a result against document version V, return that result regardless of whether didChange for V+1 (or later) has since arrived. Only return -32801 if the document
modification was genuinely external / out-of-band — which is rare in normal usage and not what didChange represents.

If pre-empting in-flight requests on didChange is desired as an optimization, the spec-compliant signal is for the client to send $/cancelRequest. The server should not unilaterally short-circuit valid in-flight work with -32801.

Per the spec, the client is supposed to handle staleness via cancellation. With lua-language-server pre-empting that decision and erroring instead:

  • Clients that handle -32801 strictly as an error end up logging spurious errors (cf. neovim/neovim#40208).
  • Clients that could have used the older-version result (perfectly valid per the spec — "even computed on an older state might still be useful") never get the chance.
  • Clients that wanted to cancel can no longer rely on $/cancelRequest semantics because the server has already aborted on its own initiative.

Actual Behaviour

Sending a fast sequence of didChanges while semantic-tokens requests are in flight causes the server to error every in-flight request with:

{ "code": -32801, "message": "Content modified." }

even though the modification was delivered through normal didChange notifications, not "outside normal conditions."

Reproduction steps

  1. Open a Lua file in any LSP-capable editor that requests semanticTokens/full (e.g. Neovim 0.12+).
  2. Start typing across multiple lines, fast enough that successive didChange notifications outpace the server's processing.
  3. Observe: every in-flight semantic-tokens request comes back with -32801 Content modified. instead of a (possibly stale) result.

Additional Notes

lua-language-server returns LSP error -32801 ("Content Modified") in response to textDocument/semanticTokens/full (and likely other requests) whenever a textDocument/didChange notification arrives before the response is sent.
This contradicts the LSP specification, which explicitly forbids using -32801 for content changes detected in unprocessed messages — i.e. for the exact case currently being signaled.

What the spec says:

LSP §responseError.code (specifically the ContentModified = -32801 entry):

The server detected that the content of a document got modified outside normal conditions. A server should NOT send this error code if it detects a content change in its unprocessed messages. The result even computed on an older
state might still be useful for the client.

If a client decides that a result is not of any use anymore the client should cancel the request.

So the intended semantics are:

  • -32801 is for "out-of-band" content modification (e.g., the file on disk changed in a way the server can't reconcile with its in-flight state).

Log File

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions