Skip to content

Conversation

Jesse-Bakker
Copy link
Contributor

Fix #30985

@github-actions github-actions bot added the lsp label Oct 30, 2024
@Jesse-Bakker Jesse-Bakker force-pushed the diagnostic-cancel branch 2 times, most recently from 9a426aa to 19b8289 Compare October 30, 2024 19:13
@MariaSolOs
Copy link
Member

I don't think this is the right fix. The LSP says that if the server sends this response we should look at the cancellation data and possibly retrigger the request: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnosticServerCancellationData. Kind of surprised that this isn't behind a client capability but this PR would be against what the protocol says we should do.

But even if we ignore the retriggering for now, I don't think we should check the code in the request handler but instead handle it here where we ignore RequestCancelled errors:

-- Do not surface RequestCancelled to users, it is RPC-internal.
if decoded.error then
local mute_error = false
if decoded.error.code == protocol.ErrorCodes.RequestCancelled then
log.debug('Received cancellation ack', decoded)
mute_error = true
end
if mute_error then
-- Clear any callback since this is cancelled now.
-- This is safe to do assuming that these conditions hold:
-- - The server will not send a result callback after this cancellation.
-- - If the server sent this cancellation ACK after sending the result, the user of this RPC
-- client will ignore the result themselves.
if result_id and message_callbacks then
message_callbacks[result_id] = nil
end
return
end
end

function M.on_diagnostic(_, result, ctx, config)
function M.on_diagnostic(error, result, ctx, config)
-- Ignore ServerCancelled error
if error ~= nil and error.code == -32802 then
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of hardcoding the code here you should be adding it to protocol's error codes:

@Jesse-Bakker
Copy link
Contributor Author

I went with handling the error in the request handler, because server-side cancellation is only defined for pull diagnostics (and semantic token requests, but that's behind a capability). The RequestCancelled error is for client-side cancellation, which is defined for all requests.

(It's not behind a client capability, because the cancellation was introduced in the same version as pull diagnostics, which means there should be no clients that implement pull diagnostics but not server-side cancellation)

Copy link
Member

@mfussenegger mfussenegger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you also add a test case?

if error ~= nil and error.code == protocol.ErrorCodes.ServerCancelled then
if error.data == nil or error.data.retriggerRequest == true then
local client = vim.lsp.get_client_by_id(ctx.client_id)
if client ~= nil then
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe an assertion that client isn’t nil is more appropriate?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible that between the first request being sent and the server cancellation being received that the client has exited? If so, silently failing when client is nil seems like the better approach I think.

@Jesse-Bakker Jesse-Bakker marked this pull request as draft November 1, 2024 09:38
@github-actions github-actions bot removed the request for review from mfussenegger November 1, 2024 09:41
@MariaSolOs
Copy link
Member

Hey @Jesse-Bakker, it seems like a lot of people are still struggling with #30985. Are you having issues with this PR? Let us know and we can help :)

if error.data == nil or error.data.retriggerRequest == true then
local client = vim.lsp.get_client_by_id(ctx.client_id)
if client ~= nil then
client.request(ctx.method, ctx.params)
Copy link
Contributor

@lithammer lithammer Nov 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not 100% sure but I think this should be:

Suggested change
client.request(ctx.method, ctx.params)
client:request(ctx.method, ctx.params)

@gpanders
Copy link
Member

Kind of surprised that this isn't behind a client capability but this PR would be against what the protocol says we should do.

Extra surprising since there is a serverCancelSupport field in SemanticTokensClientCapabilities (which we set to false!)

@gpanders
Copy link
Member

Will continue this in #31345. Thank you @Jesse-Bakker for your contribution!

@gpanders gpanders closed this Nov 25, 2024
@MariaSolOs
Copy link
Member

Kind of surprised that this isn't behind a client capability but this PR would be against what the protocol says we should do.

Extra surprising since there is a serverCancelSupport field in SemanticTokensClientCapabilities (which we set to false!)

Yeah this feels like a gap in the protocol.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

LSP: rust_analyzer: -32802: server cancelled the request
5 participants