You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
On Claude Code 2.1.207, any session whose LSP proxy starts with a fallback .venv present (the standard single-repo layout: .venv at the project root) loses LSP for the entire session:
the first LSP tool call hangs forever and cannot be interrupted with Esc,
every subsequent LSP call fails instantly with Cannot send notification to LSP server 'plugin:typemux-cc:typemux-cc': server is starting.
The proxy is not at fault: trace logs show it answered initialize 141–550 ms after receiving it, and the client then never sent another byte — not even initialized. Reproduced 3/3. The venv-less startup path (instant {"capabilities": {}} response) is unaffected (2/2), including full mid-session backend creation afterwards.
The root cause sits in Claude Code's LSP client (its state machine never leaves "starting"), but typemux-cc needs a mitigation because the affected path is the most common deployment shape.
Timeline evidence (proxy trace log, UTC)
Three wedged runs, all on the same path: fallback venv found → backend pre-spawn → handshake → full pyright capabilities returned.
run
initialize received
response written
client traffic afterwards
1
00:36:26.904
00:36:27.427 (523 ms)
none (observed >5 min)
2
00:53:51.004
00:53:51.553 (549 ms)
none
3
01:05:49.122
01:05:49.263 (141 ms)
none; user retries error client-side, nothing reaches the proxy
The response write is proven complete in each run: dispatch_initialize awaits the response write before emitting the Initial backend inserted into pool INFO line, which is present in all three runs, and the subsequent notification forwards succeeded on the same writer.
In each wedged run the proxy also forwarded 6 window/logMessage notifications from pyright ~84–94 ms after the response, i.e. before the client had sent initialized.
Healthy contrast runs (no fallback venv at startup → No fallback backend: returning minimal initialize response, <1 ms):
the client proceeded immediately (didOpen arrived 0.7 ms after the response) and all five verified operations (hover, documentSymbol, cross-file definition, references, publishDiagnostics) worked, including a mid-session uv venv with backend creation — the first hover was answered in 667 ms including spawn + handshake + document restoration (see Verify client behavior with frozen empty capabilities when starting without a fallback venv #105 verification),
a monorepo session switching across four sub-project venvs was fully functional.
Server-side health was double-checked during a hang: proxy + pyright processes alive and idle, and a scripted stdio client replaying the identical flow (initialize → initialized → didOpen → hover) against the same 0.2.17 binary received the hover answer in 0.46 s.
Trigger hypotheses (not yet discriminated)
All three differ between the wedge path and the healthy path:
the early window/logMessage notifications delivered while the client is still in its "starting" state,
something in pyright's full capabilities payload (the healthy path returns {}),
a race with initialize responses slower than ~100 ms.
Hold backend→client notifications until the client's initialized arrives. A single-variable test for hypothesis 1, and arguably safer sequencing in general.
Environment
Claude Code 2.1.207 (released 2026-07-10; the last-known-good client version is unknown — long-lived sessions started on older versions are unaffected)
Summary
On Claude Code 2.1.207, any session whose LSP proxy starts with a fallback
.venvpresent (the standard single-repo layout:.venvat the project root) loses LSP for the entire session:Cannot send notification to LSP server 'plugin:typemux-cc:typemux-cc': server is starting.The proxy is not at fault: trace logs show it answered
initialize141–550 ms after receiving it, and the client then never sent another byte — not eveninitialized. Reproduced 3/3. The venv-less startup path (instant{"capabilities": {}}response) is unaffected (2/2), including full mid-session backend creation afterwards.The root cause sits in Claude Code's LSP client (its state machine never leaves "starting"), but typemux-cc needs a mitigation because the affected path is the most common deployment shape.
Timeline evidence (proxy trace log, UTC)
Three wedged runs, all on the same path: fallback venv found → backend pre-spawn → handshake → full pyright capabilities returned.
initializereceivedThe response write is proven complete in each run:
dispatch_initializeawaits the response write before emitting theInitial backend inserted into poolINFO line, which is present in all three runs, and the subsequent notification forwards succeeded on the same writer.In each wedged run the proxy also forwarded 6
window/logMessagenotifications from pyright ~84–94 ms after the response, i.e. before the client had sentinitialized.Healthy contrast runs (no fallback venv at startup →
No fallback backend: returning minimal initialize response, <1 ms):didOpenarrived 0.7 ms after the response) and all five verified operations (hover, documentSymbol, cross-file definition, references, publishDiagnostics) worked, including a mid-sessionuv venvwith backend creation — the first hover was answered in 667 ms including spawn + handshake + document restoration (see Verify client behavior with frozen empty capabilities when starting without a fallback venv #105 verification),Server-side health was double-checked during a hang: proxy + pyright processes alive and idle, and a scripted stdio client replaying the identical flow (initialize → initialized → didOpen → hover) against the same 0.2.17 binary received the hover answer in 0.46 s.
Trigger hypotheses (not yet discriminated)
All three differ between the wedge path and the healthy path:
window/logMessagenotifications delivered while the client is still in its "starting" state,capabilitiespayload (the healthy path returns{}),initializeresponses slower than ~100 ms.Mitigation candidates
initializeimmediately with static capabilities and complete the backend handshake asynchronously. This is also the fix candidate already discussed in Verify client behavior with frozen empty capabilities when starting without a fallback venv #105; it structurally dodges hypotheses 1 and 3 and empirically tests 2.initializedarrives. A single-variable test for hypothesis 1, and arguably safer sequencing in general.Environment
An upstream report to anthropics/claude-code is drafted separately; this issue tracks the typemux-cc-side mitigation.