-
Notifications
You must be signed in to change notification settings - Fork 226
Use correct error response for cancellations #2939
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
vinistock
merged 1 commit into
main
from
11-29-use_correct_error_response_for_cancellations
Nov 29, 2024
Merged
Use correct error response for cancellations #2939
vinistock
merged 1 commit into
main
from
11-29-use_correct_error_response_for_cancellations
Nov 29, 2024
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
st0012
approved these changes
Nov 29, 2024
3f7505f to
adcfca5
Compare
vinistock
added a commit
that referenced
this pull request
Jan 8, 2025
### Motivation This is a temporary revert to fix #3019 while we understand the correct response flow for retried cancelled requests. This PR reverts the behaviour introduced in #2939, which didn't cause problems for NeoVim. ### Implementation I didn't perform a full revert of every single change, since we do want to ensure that we're following the spec. I just stopped returning the error and went back to returning a `nil` response until we figure out what's going on. ### Automated Tests Changed the test so that it asserts the current behaviour. We'll switch it back later.
This was referenced Jan 8, 2025
janko
added a commit
to janko/ruby-lsp
that referenced
this pull request
Oct 24, 2025
Ruby LSP doesn't currently cancel requests, because it processes `$/cancelRequest` notifications in the same queue as other requests, so previous requests will get processed before they get the chance to get cancelled. This was initially addressed in Shopify#2939, with cancelled requests returning an error response. This is matching the LSP spec, which requires either an incomplete or an error response. However, this started causing issues with Neovim as reported in Shopify#3019, so that implementation was ultimately reverted. The problem wasn't actually the error responses, it was that Ruby LSP was also returning a regular response, *on top of* the error response. So, a cancellation notification was resulting in *two* responses being returned for the same request, which rightfully caused errors in Neovim, as it didn't know how to handle the 2nd response. This happened because the `next` keyword breaks out of the nearest loop *or* closure, which was the `Mutex#synchronize` block, it didn't actually skip to the next iteration. This caused `process_message` to execute even if the cancel response was already sent, which ended up sending another (regular) response. To avoid introducing boolean local variables, I extracted the loop body into a separate method, so that I can just use `return` to break out. I verified that this works as expected in Zed, so I also expect it to work well in Neovim.
janko
added a commit
to janko/ruby-lsp
that referenced
this pull request
Oct 31, 2025
Ruby LSP doesn't currently cancel requests, because it processes `$/cancelRequest` notifications in the same queue as other requests, so previous requests will get processed before they get the chance to get cancelled. This was initially addressed in Shopify#2939, with cancelled requests returning an error response. This is matching the LSP spec, which requires either an incomplete or an error response. However, this started causing issues with Neovim as reported in Shopify#3019, so that implementation was ultimately reverted. The problem wasn't actually the error responses, it was that Ruby LSP was also returning a regular response, *on top of* the error response. So, a cancellation notification was resulting in *two* responses being returned for the same request, which rightfully caused errors in Neovim, as it didn't know how to handle the 2nd response. This happened because the `next` keyword breaks out of the nearest loop *or* closure, which was the `Mutex#synchronize` block, it didn't actually skip to the next iteration. This caused `process_message` to execute even if the cancel response was already sent, which ended up sending another (regular) response. To avoid introducing boolean local variables, I extracted the loop body into a separate method, so that I can just use `return` to break out. I verified that this works as expected in Zed, so I also expect it to work well in Neovim.
vinistock
pushed a commit
that referenced
this pull request
Nov 5, 2025
Ruby LSP doesn't currently cancel requests, because it processes `$/cancelRequest` notifications in the same queue as other requests, so previous requests will get processed before they get the chance to get cancelled. This was initially addressed in #2939, with cancelled requests returning an error response. This is matching the LSP spec, which requires either an incomplete or an error response. However, this started causing issues with Neovim as reported in #3019, so that implementation was ultimately reverted. The problem wasn't actually the error responses, it was that Ruby LSP was also returning a regular response, *on top of* the error response. So, a cancellation notification was resulting in *two* responses being returned for the same request, which rightfully caused errors in Neovim, as it didn't know how to handle the 2nd response. This happened because the `next` keyword breaks out of the nearest loop *or* closure, which was the `Mutex#synchronize` block, it didn't actually skip to the next iteration. This caused `process_message` to execute even if the cancel response was already sent, which ended up sending another (regular) response. To avoid introducing boolean local variables, I extracted the loop body into a separate method, so that I can just use `return` to break out. I verified that this works as expected in Zed, so I also expect it to work well in Neovim.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.

Motivation
While working on #2938, I noticed that our request cancellation response was incorrect. The spec determines that requests that got cancelled by the client need to return an error using the code for request cancelled (see here and see
RequestCancelledhere).Implementation
Started returning an error with the right code, rather than a response with a
nilbody.I also started running cancel notifications directly in the main thread without pushing it to the queue, which was another mistake. If we put that notification in the queue, then we're guaranteed to only process them after we finish running requests, which is useless. We need the ability to process them as soon as we receive the notification, so that we have enough time to cancel the requests.
Automated Tests
Added a test to verify this.