Skip to content

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

Open

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

Activity

  1. sumneko commented on Jun 24, 2026

    @sumneko
    Collaborator

    我理解你的意思,不过我目前暂时不知道如何正确处理。
    目前的实现中,全局共享了同一个语义状态。
    当文件变化后,这个语义状态就被更新了,而处理了一半的旧请求可能依赖了旧的状态,可能会产生预料外的错误。

    要不我先尝试直接去掉这个行为,你们测试一下有没有明显的问题?

  2. Issues-translate-bot commented on Jun 24, 2026

    @Issues-translate-bot

    Sumneko Lua translate bot


    I understand what you mean, but I don't know how to handle it correctly at the moment.
    In the current implementation, the same semantic state is globally shared.
    When the file changes, this semantic state is updated, and old requests that are half processed may rely on the old state, which may cause unexpected errors.

    How about I try to remove this behavior directly first, and then you can test it and see if there are any obvious problems?

  3. added a commit that references this issue on Jun 24, 2026
  4. ofseed commented on Jun 24, 2026

    @ofseed
    Contributor

    看了下 39bb895,似乎会导致请求收不到回复?

    目前确实不会有太大问题,但其实只是 neovim (还)没有处理这个情况,有留下一条TODO:
    https://github.com/neovim/neovim/blob/master/runtime/lua/vim/lsp/rpc.lua#L429-L431

    要不然包括 neovim 的大多数 client 都应该会保留一些已经发出去的状态数据(例如收到请求后的回调),不会回复的请求可能会导致一定程度的内存泄露。

  5. Issues-translate-bot commented on Jun 24, 2026

    @Issues-translate-bot

    Sumneko Lua translate bot


    After looking at 39bb895, it seems that the request will not receive a reply?

    There really won’t be much of a problem at the moment, but it’s just that neovim has not (yet) handled this situation, leaving a TODO:
    https://github.com/neovim/neovim/blob/master/runtime/lua/vim/lsp/rpc.lua#L429-L431

    Otherwise, most clients, including neovim, should retain some status data that has been sent (such as callbacks after receiving requests), and requests that do not respond may lead to a certain degree of memory leaks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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