Skip to content

Commit 86e8927

Browse files
committed
feat: remove "initializeResult unexpectedly null after initialization"
exception this reduces the number of exceptions during LSP4E operations. As an example of such an exception is: !ENTRY org.eclipse.lsp4e 4 0 2026-04-20 09:22:31.360 !MESSAGE java.lang.IllegalStateException: serverCapabilities unexpectedly null after initialization !STACK 0 java.util.concurrent.CompletionException: java.lang.IllegalStateException: serverCapabilities unexpectedly null after initialization at java.base/java.util.concurrent.CompletableFuture.encodeRelay(CompletableFuture.java:368) at java.base/java.util.concurrent.CompletableFuture.uniComposeStage(CompletableFuture.java:1189) at java.base/java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:2341) at org.eclipse.lsp4e.LanguageServerWrapper.getServerCapabilitiesAsync(LanguageServerWrapper.java:1120) at org.eclipse.lsp4e.LanguageServers$LanguageServerDocumentExecutor.filter(LanguageServers.java:282) ... at org.eclipse.lsp4e.LanguageServers$LanguageServerDocumentExecutor.getServers(LanguageServers.java:290) at org.eclipse.lsp4e.LanguageServers.executeOnServers(LanguageServers.java:441) at org.eclipse.lsp4e.LanguageServers.collectAll(LanguageServers.java:92) at org.eclipse.lsp4e.LanguageServers.collectAll(LanguageServers.java:75) at org.eclipse.lsp4e.operations.linkedediting.LSPLinkedEditingBase.collectLinkedEditingRanges(LSPLinkedEditingBase.java:72) at org.eclipse.lsp4e.operations.linkedediting.LSPLinkedEditingReconcilingStrategy.updateLinkedEditing(LSPLinkedEditingReconcilingStrategy.java:168) at org.eclipse.lsp4e.operations.linkedediting.LSPLinkedEditingReconcilingStrategy.updateLinkedEditing(LSPLinkedEditingReconcilingStrategy.java:156) at org.eclipse.lsp4e.operations.linkedediting.LSPLinkedEditingReconcilingStrategy.lambda$0(LSPLinkedEditingReconcilingStrategy.java:134) ...
1 parent e6399b1 commit 86e8927

6 files changed

Lines changed: 34 additions & 27 deletions

File tree

org.eclipse.lsp4e/src/org/eclipse/lsp4e/DocumentContentSynchronizer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ private void formatDocument() {
318318
return languageServerWrapper.getServerCapabilitiesAsync().thenCompose(capabilities -> {
319319
FormattingOptions formatOptions = LSPFormatter.getFormatOptions();
320320
final var docId = new TextDocumentIdentifier(fileUri.toString());
321-
if (LSPFormatter.isDocumentRangeFormattingSupported(capabilities)
321+
if (capabilities != null && LSPFormatter.isDocumentRangeFormattingSupported(capabilities)
322322
&& !(LSPFormatter.isDocumentFormattingSupported(capabilities) && textSelection.getLength() == 0)) {
323323
try {
324324
DocumentRangeFormattingParams rangeParams = LSPFormatter.getRangeFormattingParams(document,

org.eclipse.lsp4e/src/org/eclipse/lsp4e/LanguageServerWrapper.java

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,17 +1079,14 @@ public void sendNotification(Consumer<LanguageServer> fn) {
10791079
return res;
10801080
}
10811081

1082-
public CompletableFuture<InitializeResult> getInitializeResultAsync() {
1083-
return getInitializedServer().thenCompose(ls -> {
1084-
final var initializeResult = this.initializeResult;
1085-
if (initializeResult == null) {
1086-
// This can happen if the server shuts down immediately after initialization,
1087-
// but before this callback was invoked.
1088-
return CompletableFuture.failedFuture(
1089-
new IllegalStateException("initializeResult unexpectedly null after initialization")); //$NON-NLS-1$
1090-
}
1091-
return CompletableFuture.completedFuture(initializeResult);
1092-
});
1082+
/**
1083+
* @return a {@link CompletableFuture} that provides the {@link InitializeResult}.
1084+
* <p>
1085+
* The {@link InitializeResult} will be {@code null} if the server shuts down
1086+
* immediately after initialization or if it fails to start.
1087+
*/
1088+
public CompletableFuture<@Nullable InitializeResult> getInitializeResultAsync() {
1089+
return getInitializedServer().thenCompose(ls -> CompletableFuture.completedFuture(this.initializeResult));
10931090
}
10941091

10951092
/**
@@ -1116,17 +1113,14 @@ public CompletableFuture<InitializeResult> getInitializeResultAsync() {
11161113
return this.serverCapabilities;
11171114
}
11181115

1119-
public CompletableFuture<ServerCapabilities> getServerCapabilitiesAsync() {
1120-
return getInitializedServer().thenCompose(ls -> {
1121-
final var serverCapabilities = this.serverCapabilities;
1122-
if (serverCapabilities == null) {
1123-
// This can happen if the server shuts down immediately after initialization,
1124-
// but before this callback was invoked.
1125-
return CompletableFuture.failedFuture(
1126-
new IllegalStateException("serverCapabilities unexpectedly null after initialization")); //$NON-NLS-1$
1127-
}
1128-
return CompletableFuture.completedFuture(serverCapabilities);
1129-
});
1116+
/**
1117+
* @return a {@link CompletableFuture} that provides the {@link ServerCapabilities}.
1118+
* <p>
1119+
* The {@link ServerCapabilities} will be {@code null} if the server shuts down
1120+
* immediately after initialization or if it fails to start.
1121+
*/
1122+
public CompletableFuture<@Nullable ServerCapabilities> getServerCapabilitiesAsync() {
1123+
return getInitializedServer().thenCompose(ls -> CompletableFuture.completedFuture(this.serverCapabilities));
11301124
}
11311125

11321126
public CompletableFuture<@Nullable ServerInfo> getServerInfoAsync() {

org.eclipse.lsp4e/src/org/eclipse/lsp4e/LanguageServers.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,9 @@ public E withFilter(final Predicate<ServerCapabilities> filter) {
206206
* @param serverCapabilities
207207
*/
208208
@SuppressWarnings("unchecked")
209-
public E withCapability(final Function<ServerCapabilities, Either<Boolean, ?>> serverCapabilities) {
209+
public E withCapability(final @Nullable Function<ServerCapabilities, Either<Boolean, ?>> serverCapabilities) {
210210
Assert.isLegal(this.filter == NO_FILTER);
211-
this.filter = f -> LSPEclipseUtils.hasCapability(serverCapabilities.apply(f));
211+
this.filter = f -> serverCapabilities != null && LSPEclipseUtils.hasCapability(serverCapabilities.apply(f));
212212
return (E) this;
213213
}
214214

@@ -280,7 +280,7 @@ public IDocument getDocument() {
280280
*/
281281
private CompletableFuture<@Nullable LanguageServerWrapper> filter(LanguageServerWrapper wrapper) {
282282
return wrapper.getServerCapabilitiesAsync() //
283-
.thenApply(sc -> getFilter().test(sc) ? wrapper : null);
283+
.thenApply(sc -> sc != null && getFilter().test(sc) ? wrapper : null);
284284
}
285285

286286
@Override

org.eclipse.lsp4e/src/org/eclipse/lsp4e/LanguageServiceAccessor.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ private LSPDocumentInfo(URI fileUri, IDocument document, LanguageServerWrapper w
9494
this.wrapper = wrapper;
9595
}
9696

97+
@Deprecated
9798
public IDocument getDocument() {
9899
return this.document;
99100
}
@@ -103,22 +104,27 @@ public IDocument getDocument() {
103104
*
104105
* @return the file URI
105106
*/
107+
@Deprecated
106108
public URI getFileUri() {
107109
return this.fileUri;
108110
}
109111

112+
@Deprecated
110113
public LanguageServerWrapper getLanguageServerWrapper() {
111114
return wrapper;
112115
}
113116

117+
@Deprecated
114118
public int getVersion() {
115119
return wrapper.getTextDocumentVersion(fileUri);
116120
}
117121

122+
@Deprecated
118123
public @Nullable ServerCapabilities getCapabilites() {
119124
return this.wrapper.getServerCapabilities();
120125
}
121126

127+
@Deprecated
122128
public boolean isActive() {
123129
return this.wrapper.isActive();
124130
}
@@ -220,7 +226,7 @@ private static CompletableFuture<Boolean> capabilitiesComplyAsync(final Language
220226
final @Nullable Predicate<ServerCapabilities> capabilitiesPredicate) {
221227
return capabilitiesPredicate == null //
222228
? CompletableFuture.completedFuture(true) //
223-
: wrapper.getServerCapabilitiesAsync().thenApply(capabilitiesPredicate::test);
229+
: wrapper.getServerCapabilitiesAsync().thenApply(sC -> sC != null && capabilitiesPredicate.test(sC));
224230
}
225231

226232
/**

org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codelens/LSPCodeMining.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ public LSPCodeMining(CodeLens codeLens, IDocument document, LanguageServerWrappe
5252
@Override
5353
protected CompletableFuture<@Nullable Void> doResolve(ITextViewer viewer, IProgressMonitor monitor) {
5454
return languageServerWrapper.getServerCapabilitiesAsync().thenCompose(capabilities -> {
55+
if (capabilities == null) {
56+
return CompletableFuture.completedFuture(null);
57+
}
5558
final Boolean resolveProvider = capabilities.getCodeLensProvider().getResolveProvider();
5659
if (resolveProvider == null || !resolveProvider) {
5760
return CompletableFuture.completedFuture(null);

org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/format/LSPFormatter.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ public CompletableFuture<Optional<VersionedEdits>> requestFormatting(IDocument d
5757
// can fall through to the next server (e.g. Vue LS after TS LS on .vue files).
5858
long modificationStamp = DocumentUtil.getDocumentModificationStamp(document);
5959
return executor.computeFirst((w, ls) -> w.getServerCapabilitiesAsync().thenCompose(capabilities -> {
60+
if (capabilities == null) {
61+
return CompletableFuture.completedFuture(null);
62+
}
63+
6064
if (isDocumentRangeFormattingSupported(capabilities) && (textSelection.getLength() > 0 || !isDocumentFormattingSupported(capabilities))) {
6165
return (CompletableFuture<@Nullable List<? extends TextEdit>>) ls.getTextDocumentService()
6266
.rangeFormatting(rangeParams);

0 commit comments

Comments
 (0)