feat(lsp): capture server stderr to diagnose init failures

drainStderr discarded all server stderr, so an LSP init failure (e.g. 'command not found', missing module) surfaced as an opaque 'initialization failed'. Retain a bounded tail (StderrCaptureMax=4096B, oldest dropped) under a mutex and attach it to the init-failure error context. Adds TestClientStderrCapture.
This commit is contained in:
2026-06-20 00:33:33 +01:00
parent 13b1a22102
commit 1b41e43bf3
3 changed files with 64 additions and 3 deletions
+7 -1
View File
@@ -212,10 +212,16 @@ func (m *Manager) GetServer(ctx context.Context, lang protocol.Language) (*Manag
// Initialize server
if err := m.initializeServer(ctx, newSrv); err != nil {
newSrv.initErr = err
return nil, errors.Wrap(errors.ErrLSPInitFailed, "LSP server initialization failed", err).
wrapped := errors.Wrap(errors.ErrLSPInitFailed, "LSP server initialization failed", err).
WithContext("language", string(lang)).
WithContext("command", config.Command[0]).
WithRemediation("Check LSP server logs for initialization errors")
// Surface the server's own stderr (e.g. "command not found", missing
// module) so the failure is diagnosable instead of opaque.
if stderr := client.RecentStderr(); stderr != "" {
wrapped = wrapped.WithContext("stderr", stderr)
}
return nil, wrapped
}
// Mark as successfully initialized to prevent cleanup