LuaLS / LuaLS/lua-language-server

noisy `-32801` ("Content Modified") errors

Open
#3,420 4 comments 6 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
Lua
Stars
4.4k
Forks
442
PR merge metrics
No merged PRs in 30d

Description

### 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](https://github.com/neovim/neovim/issues/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 `didChange`s while semantic-tokens requests are in flight causes the server to error every in-flight request with:

```json
{ "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](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#responseError) (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_

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing the textDocument/semanticTokens/full request path and how textDocument/didChange notifications affect in-flight requests. Compare that behavior with the LSP responseError.code specification; done means normal queued document changes no longer produce -32801, while genuinely external modifications still can.

Written by the indexing model from the issue text.

Assessment

Tech stack
lua, neovim
Domain
devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.