fix: LSP handshake race condition, duplicate notification, and slow-start timeout#127
Open
marcelmaatkamp wants to merge 3 commits intoisaacphi:mainfrom
Open
fix: LSP handshake race condition, duplicate notification, and slow-start timeout#127marcelmaatkamp wants to merge 3 commits intoisaacphi:mainfrom
marcelmaatkamp wants to merge 3 commits intoisaacphi:mainfrom
Conversation
Initialize the LSP process in a background goroutine so ServeStdio starts immediately. Tool handlers block via waitForLSP() until the LSP is ready. Fixes timeout with slow-starting LSPs like Kotlin (~95s Gradle sync on first run). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
initialized was sent twice: once via Notify before handler registration and once via c.Initialized() after. The duplicate confused Kotlin LSP, causing 'kotlin.Nothing' does not have instances errors on all requests. Handler registration is now done before the single initialized call. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
workspace/configuration and other server requests can arrive at any time during the initialize handshake. Registering handlers after initialize caused 'method not found' responses, putting Kotlin LSP in a bad state which produced 'kotlin.Nothing' does not have instances errors. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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
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.
Summary
Three related fixes found while integrating the Kotlin LSP (
fwcd/kotlin-language-server). All three affect any LSP that sends server-initiated requests during the handshake or takes a long time to start.Fix 1: Register handlers before
initialize(race condition)The LSP spec allows servers to send requests like
workspace/configurationat any point after receivinginitialize— including before the client sendsinitialized. The previous code registered handlers after theinitializecall returned, so these requests arrived with no handler and got amethod not foundresponse. This put the server in a bad state for all subsequent requests.Fix: Move handler registration to before the
initializecall.Fix 2: Remove duplicate
initializednotificationinitializedwas being sent twice: once via an explicitNotifycall and once viac.Initialized(). Strict LSP servers (like Kotlin) treat this as a protocol error, causing all subsequent requests to fail with nonsensical errors (kotlin.Nothing does not have instances).Fix: Remove the duplicate
Notifycall, keep onlyc.Initialized().Fix 3: Lazy LSP initialization to avoid MCP timeout
ServeStdio()was only called afterInitializeLSPClient()completed. For LSPs with slow startup (Kotlin triggers a Gradle sync, ~95s on first run), this exceeded the MCP client's 120s timeout before the server was even reachable.Fix: Initialize the LSP in a background goroutine so
ServeStdio()starts immediately. Tool handlers block viawaitForLSP()until the LSP is ready, making the timeout apply per tool call rather than at startup.Test plan
fwcd/kotlin-language-serverv1.3.13 against a real Gradle projecthover,definition,references, anddiagnosticstools all return correct resultsinitializeandtools/listimmediately, before LSP is ready🤖 Generated with Claude Code