Environment
- OS: macOS (aarch64), Darwin 25.5.0
- Eclipse Version: 4.40.0.20260604-0652 (Eclipse IDE for Enterprise Java and Web Developers), LSP4E
0.19.12.202605060644, Java (Eclipse Adoptium) 21.0.11
- Plugin Version:
0.20.0.202607100822 (also reproduced on 0.20.0.202607100750_nightly); GitHub Copilot Language Server 1.509.5 (Node.js 22.22.3)
Describe the bug
After the very first conversation/templates LSP request succeeds, subsequent calls to the same method never receive a response from the GitHub Copilot Language Server, even though other request types sent in the same time window continue to resolve normally — so the LS process and JSON-RPC channel are not globally hung, only conversation/templates stops being answered after its first success.
Because ChatCompletionService.initConversationTemplates() calls CompletableFuture#get() with no timeout (and ModelService.fetchByokModels() has the identical pattern for listByokModels), the Eclipse Job worker thread that issued the request parks forever (WAITING on CompletableFuture$Signaller). Since Eclipse's Job.cancel() only flips an IProgressMonitor flag and cannot interrupt a thread already blocked inside CompletableFuture#get(), every time fetchAsync() fires again (e.g. on SKILL.md / *.prompt.md resource-change events) a new stuck worker thread accumulates and is never reclaimed. This has been observed to persist across Eclipse restarts — Eclipse's own shutdown handler logs "Job found still running after platform shutdown" for the same stuck job on repeated sessions.
Traced via decompilation of the plugin/LSP4E jars, the call chain has no timeout anywhere:
ChatCompletionService.initConversationTemplates()
-> this.lsConnection.listConversationTemplates(workspaceFolders).get() // NO TIMEOUT
CopilotLanguageServerConnection.listConversationTemplates()
-> this.languageServerWrapper.execute(fn) // LSP4E
LanguageServerWrapper.execute() -> executeImpl() -> getInitializedServer() -> start()
// none of these apply any timeout to the eventual server response
Two compounding issues:
- Server-side: whatever handles
conversation/templates inside the Copilot Language Server appears to stop responding to that method after the first successful call in a session (root cause not visible from the client side — needs LS-side investigation; looks like a debounce/memoization/in-flight-promise bug keyed by request method rather than by request id).
- Client-side: because
.get() has no timeout anywhere in the call chain, and job cancellation cannot interrupt a thread already parked in .get(), a single unanswered request permanently strands a worker thread. Repeated triggers (e.g. many resource-change events in a multi-root workspace) accumulate multiple stuck threads per session.
To Reproduce
- Open Eclipse with a multi-root workspace containing custom
SKILL.md / *.prompt.md files across several projects (this appears to increase the chance of fetchAsync() firing multiple times in quick succession during startup).
- Sign in to Copilot and let the workspace finish loading/indexing.
- Enable LSP4E tracing (
Preferences > Language Servers > Logs, enable "Log to File" for server id com.microsoft.copilot.eclipse.ls) to capture the raw JSON-RPC traffic.
- Observe in the trace log that the first
conversation/templates request/response pair succeeds:
--> {"jsonrpc":"2.0","id":"4","method":"conversation/templates","params":{"workspaceFolders":[...]}}
<-- {"jsonrpc":"2.0","id":"4","result":[{"id":"tests", ...}, ...]} // full template list returned correctly
- Watch for later
conversation/templates requests (fired again by fetchAsync()), e.g.:
--> {"jsonrpc":"2.0","id":"24","method":"conversation/templates","params":{...}} // never answered
--> {"jsonrpc":"2.0","id":"32","method":"conversation/templates","params":{...}} // never answered
These never receive a matching response, while other concurrent request ids in the same window (e.g. id=23, id=17, id=14, id=31) resolve normally.
- Take a Java thread dump of the Eclipse process; a
Worker-N: Refresh slash commands service thread is permanently WAITING inside ChatCompletionService.initConversationTemplates:
"Worker-14: Refresh slash commands service" #102 prio=5 ... elapsed=247.05s ... waiting on condition
java.lang.Thread.State: WAITING (parking)
at jdk.internal.misc.Unsafe.park(Native Method)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:221)
at java.util.concurrent.CompletableFuture$Signaller.block(CompletableFuture.java:1864)
at java.util.concurrent.ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3780)
at java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3725)
at java.util.concurrent.CompletableFuture.waitingGet(CompletableFuture.java:1898)
at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2072)
at com.microsoft.copilot.eclipse.ui.chat.services.ChatCompletionService.initConversationTemplates(ChatCompletionService.java:126)
at com.microsoft.copilot.eclipse.ui.chat.services.ChatCompletionService$1.run(ChatCompletionService.java:99)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:63)
Expected behavior
conversation/templates should keep responding on every call for the lifetime of the session (or at minimum, the client should time out and recover instead of hanging a worker thread forever). Slash-command / template data in the chat panel should keep refreshing instead of silently freezin
g after the first successful fetch, and ChatCompletionService.isTempaltesReady() should not get permanently stuck once this happens.
Screenshots
N/A — this is a backend/threading hang with no visible UI error. Happy to attach the full sanitized LSP trace log and a Java thread dump on request.
Additional context
- The exact same hang has recurred across multiple Eclipse restarts in our environment: at previous sessions' shutdown, Eclipse's own job manager logged the same stuck stack trace for
ChatCompletionService$1, and — via the identical lsConnection.xxx().get() pattern with no timeout — for
ModelService$1 (ModelService.fetchByokModels, ModelService.java:220) as well:
!ENTRY org.eclipse.core.jobs 2 2 2026-07-24 06:29:30.048
!MESSAGE Job found still running after platform shutdown. ...: com.microsoft.copilot.eclipse.ui.chat.services.ChatCompletionService$1 RUNNING
at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2072)
at com.microsoft.copilot.eclipse.ui.chat.services.ChatCompletionService.initConversationTemplates(ChatCompletionService.java:126)
at com.microsoft.copilot.eclipse.ui.chat.services.ChatCompletionService$1.run(ChatCompletionService.java:99)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:63)
!ENTRY org.eclipse.core.jobs 2 2 2026-07-24 06:29:30.048
!MESSAGE Job found still running after platform shutdown. ...: com.microsoft.copilot.eclipse.ui.chat.services.ModelService$1 RUNNING
at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2072)
at com.microsoft.copilot.eclipse.ui.chat.services.ModelService.fetchByokModels(ModelService.java:220)
at com.microsoft.copilot.eclipse.ui.chat.services.ModelService$1.run(ModelService.java:176)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:63)
- Suggested fixes:
- Investigate why the Copilot Language Server only answers the first
conversation/templates request per session and silently drops subsequent ones.
- On the extension side, add a bounded timeout (e.g.
.get(30, TimeUnit.SECONDS)) to the blocking calls in ChatCompletionService.initConversationTemplates and ModelService.fetchByokModels (and audit other similar lsConnection.xxx().get() call sites), logging/reporting a timeout ins
tead of hanging forever.
- Make
fetchAsync()'s job cancellation actually propagate to the in-flight CompletableFuture (e.g. keep a reference and call .cancel(true) on it) instead of only cancelling the IProgressMonitor, which has no effect on a thread already inside .get().
Environment
0.19.12.202605060644, Java (Eclipse Adoptium)21.0.110.20.0.202607100822(also reproduced on0.20.0.202607100750_nightly); GitHub Copilot Language Server1.509.5(Node.js22.22.3)Describe the bug
After the very first
conversation/templatesLSP request succeeds, subsequent calls to the same method never receive a response from the GitHub Copilot Language Server, even though other request types sent in the same time window continue to resolve normally — so the LS process and JSON-RPC channel are not globally hung, onlyconversation/templatesstops being answered after its first success.Because
ChatCompletionService.initConversationTemplates()callsCompletableFuture#get()with no timeout (andModelService.fetchByokModels()has the identical pattern forlistByokModels), the EclipseJobworker thread that issued the request parks forever (WAITINGonCompletableFuture$Signaller). Since Eclipse'sJob.cancel()only flips anIProgressMonitorflag and cannot interrupt a thread already blocked insideCompletableFuture#get(), every timefetchAsync()fires again (e.g. onSKILL.md/*.prompt.mdresource-change events) a new stuck worker thread accumulates and is never reclaimed. This has been observed to persist across Eclipse restarts — Eclipse's own shutdown handler logs "Job found still running after platform shutdown" for the same stuck job on repeated sessions.Traced via decompilation of the plugin/LSP4E jars, the call chain has no timeout anywhere:
Two compounding issues:
conversation/templatesinside the Copilot Language Server appears to stop responding to that method after the first successful call in a session (root cause not visible from the client side — needs LS-side investigation; looks like a debounce/memoization/in-flight-promise bug keyed by request method rather than by request id)..get()has no timeout anywhere in the call chain, and job cancellation cannot interrupt a thread already parked in.get(), a single unanswered request permanently strands a worker thread. Repeated triggers (e.g. many resource-change events in a multi-root workspace) accumulate multiple stuck threads per session.To Reproduce
SKILL.md/*.prompt.mdfiles across several projects (this appears to increase the chance offetchAsync()firing multiple times in quick succession during startup).Preferences > Language Servers > Logs, enable "Log to File" for server idcom.microsoft.copilot.eclipse.ls) to capture the raw JSON-RPC traffic.conversation/templatesrequest/response pair succeeds:conversation/templatesrequests (fired again byfetchAsync()), e.g.:id=23,id=17,id=14,id=31) resolve normally.Worker-N: Refresh slash commands servicethread is permanentlyWAITINGinsideChatCompletionService.initConversationTemplates:Expected behavior
conversation/templatesshould keep responding on every call for the lifetime of the session (or at minimum, the client should time out and recover instead of hanging a worker thread forever). Slash-command / template data in the chat panel should keep refreshing instead of silently freezing after the first successful fetch, and
ChatCompletionService.isTempaltesReady()should not get permanently stuck once this happens.Screenshots
N/A — this is a backend/threading hang with no visible UI error. Happy to attach the full sanitized LSP trace log and a Java thread dump on request.
Additional context
ChatCompletionService$1, and — via the identicallsConnection.xxx().get()pattern with no timeout — forModelService$1(ModelService.fetchByokModels,ModelService.java:220) as well:conversation/templatesrequest per session and silently drops subsequent ones..get(30, TimeUnit.SECONDS)) to the blocking calls inChatCompletionService.initConversationTemplatesandModelService.fetchByokModels(and audit other similarlsConnection.xxx().get()call sites), logging/reporting a timeout instead of hanging forever.
fetchAsync()'s job cancellation actually propagate to the in-flightCompletableFuture(e.g. keep a reference and call.cancel(true)on it) instead of only cancelling theIProgressMonitor, which has no effect on a thread already inside.get().