redhat-developer / redhat-developer/lsp4ij

Ongoing futures never complete when LSP server crashes

Open
#1,565 5 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Java
Stars
344
Forks
113
Avg merge
5h 22m
Merged PRs (30d)
15

Description

When the LSP server crashes or terminates unexpectedly, the ongoing futures for pending requests (such as Hover, Completion, Diagnostics, etc.) are never explicitly cancelled by LSP4IJ and can hang indefinitely (never completing).

Here is a detailed breakdown of the codebase research confirming this behavior and explaining why it happens:

1. Ongoing Futures are Owned by LSPFileSupport (Persisting on PsiFile)
  • Ongoing request futures (e.g., LSPCompletionSupport, LSPHoverSupport) are managed by subclasses of AbstractLSPFeatureSupport which are held by LSPFileSupport (LSPFileSupport.java).
  • LSPFileSupport is attached as user data to each open PsiFile (file.putUserData(LSP_FILE_SUPPORT_KEY, this)).
  • It is registered with the Project Disposer:
    Disposer.register(file.getProject(), this);
    
    This means the feature supports and their cached futures are only disposed when the entire IntelliJ project is closed, not when the LSP server stops or crashes.
2. LanguageServerWrapper Does Not Track or Cancel Feature Futures
  • When the LSP server terminates/crashes unexpectedly, the unexpectedServerStopHandler triggers the stop() sequence in LanguageServerWrapper (LanguageServerWrapper.java:L1603).
  • stop() disposes the languageClient, disposes the DocumentContentSynchronizer for all opened documents, and cancels the launcher listening thread.
  • However, LanguageServerWrapper does not maintain references to the individual request futures (e.g., completion, document symbols) created by the various AbstractLSPFeatureSupport components. Consequently, it does not cancel or fail them.
3. LSP4J Abrupt Stream Closure Pitfalls
  • Under normal circumstances, LSP4J's RemoteEndpoint tracks outstanding request futures.
  • However, if the LSP server process crashes or is killed abruptly, the stream throws a sudden IOException (such as a Broken Pipe). In these scenarios, LSP4J does not automatically cancel or complete outstanding request futures in all code paths unless the graceful shutdown/cleanup protocol completes.
  • Any future that does not get completed exceptionally by LSP4J will remain in an unresolved state permanently.
4. Server Status Changes are Not Propagated to Active Feature Supports
  • Although LanguageServerWrapper.updateStatus() triggers status updates like ServerStatus.stopping or ServerStatus.stopped, the handleServerStatusChanged() hooks in LanguageClientImpl and LSPClientFeatures are empty placeholders:
    public void handleServerStatusChanged(@NotNull ServerStatus serverStatus) {
        // Do nothing
    }
    
  • There is no listener or event propagation mechanism to inform active AbstractLSPFeatureSupport instances that the server has terminated, so they never call cancel() to clear and reject their pending CancellationSupport and CompletableFuture states.

Summary of Impact

Because the wrapper has no tracking of these feature-specific futures and the LSPFileSupport remains alive on the PsiFile without receiving status updates, any pending futures that LSP4J fails to resolve will hang indefinitely. Any part of the IDE awaiting these futures (using .get(), .join(), or awaitWithCheckCanceled()) will continue to block or leak memory.

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 with LSPFileSupport.java and LanguageServerWrapper.java, focusing on the unexpectedServerStopHandler, stop(), updateStatus(), and the server-status hooks in LanguageClientImpl and LSPClientFeatures. Trace how AbstractLSPFeatureSupport instances retain pending futures and define completion or cancellation behavior for requests after an unexpected server stop. Done means pending requests no longer hang indefinitely when the LSP server crashes.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
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.