on main help sign in
fix(lsp): prevent nil client from being stored in clients map (#2262)
commit0a2a3feb6da2f665e5d590736bc28fce1bd1d38b authorAustin Cherry <acmacalister@gmail.com> dateFri 20 Feb 2026, 07:09 (8 months ago) parent3a7d79f
1 file changed+28−14
internal/lsp/manager.go+28−14
internal/lsp/manager.go+28−14
@@ -178,24 +178,38 @@ func (s *Manager) startServer(ctx context.Context, name, filepath string, server
178178 return
179179 }
180180
181− // check again in case another goroutine started it in the meantime
182− var err error
183− client := s.clients.GetOrSet(name, func() *Client {
184− var cli *Client
185− cli, err = New(
186− ctx,
187− name,
188− cfg,
189− s.cfg.Resolver(),
190− s.cfg.WorkingDir(),
191− s.cfg.Options.DebugLSP,
192− )
193− return cli
194− })
181+ // Check again in case another goroutine started it in the meantime.
182+ if client, ok := s.clients.Get(name); ok {
183+ switch client.GetServerState() {
184+ case StateReady, StateStarting, StateDisabled:
185+ s.callback(name, client)
186+ return
187+ }
188+ }
189+
190+ client, err := New(
191+ ctx,
192+ name,
193+ cfg,
194+ s.cfg.Resolver(),
195+ s.cfg.WorkingDir(),
196+ s.cfg.Options.DebugLSP,
197+ )
195198 if err != nil {
196199 slog.Error("Failed to create LSP client", "name", name, "error", err)
197200 return
198201 }
202+ // Only store non-nil clients. If another goroutine raced us,
203+ // prefer the already-stored client.
204+ if existing, ok := s.clients.Get(name); ok {
205+ switch existing.GetServerState() {
206+ case StateReady, StateStarting, StateDisabled:
207+ client.Close(ctx)
208+ s.callback(name, existing)
209+ return
210+ }
211+ }
212+ s.clients.Set(name, client)
199213 defer func() {
200214 s.callback(name, client)
201215 }()