charmbracelet/crush · error
failed to shutdown server: %v
Error message
failed to shutdown server: %v
What it means
During graceful shutdown, srv.Shutdown(ctx) waits (bounded by the deferred context) for active connections to finish. If it returns an error (context deadline exceeded or a forced close failure), the command logs it and returns this wrapped error instead of exiting cleanly.
Source
Thrown at internal/cmd/server.go:94
if err != nil && !errors.Is(err, server.ErrServerClosed) {
_ = srv.Close()
slog.Error("Server error", "error", err)
return fmt.Errorf("server error: %v", err)
}
}
if errors.Is(err, server.ErrServerClosed) {
return nil
}
ctx, cancel := context.WithTimeout(cmd.Context(), 5*time.Second)
defer cancel()
slog.Info("Shutting down...")
if err := srv.Shutdown(ctx); err != nil {
slog.Error("Failed to shutdown server", "error", err)
return fmt.Errorf("failed to shutdown server: %v", err)
}
return nil
},
}
View on GitHub (pinned to 7944b8e522)
Solutions
- Increase the shutdown context timeout to allow in-flight requests to complete
- Investigate and close long-lived connections (websockets/streaming) before Shutdown
- Call srv.Close() as a forced fallback after Shutdown fails, and log remaining connections
- Check the 'Failed to shutdown server' log line for the exact underlying cause (usually context deadline exceeded)
Example fix
// before
ctx := context.Background()
if err := srv.Shutdown(ctx); err != nil { ... }
// after
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
_ = srv.Close() // force close lingering connections
return fmt.Errorf("failed to shutdown server: %w", err)
} Defensive patterns
Strategy: try-catch
Try / catch
if err := srv.Shutdown(ctx); err != nil {
if errors.Is(err, context.DeadlineExceeded) {
slog.Warn("Graceful shutdown timed out; forcing close")
_ = srv.Close()
return nil
}
return fmt.Errorf("failed to shutdown server: %w", err)
} Prevention
- Give Shutdown a generous timeout context (5-30s)
- Track and close long-lived connections (websockets) on shutdown signals
- Fall back to srv.Close() after a failed graceful shutdown
- Log the underlying error before wrapping to aid diagnosis
When it happens
Trigger: SIGINT/SIGTERM triggers the shutdown path; srv.Shutdown returns an error because the shutdown context is canceled/expired before idle connections drain, or an underlying listener close fails.
Common situations: In-flight requests or stuck connections (websockets, long polls) keep the server busy past the shutdown timeout; user presses Ctrl-C twice; shutdown context too short.
Related errors
- server error: %v
- cannot continue an agent tool session: %s
- session not found: %s
- cannot continue a child session: %s
- no sessions found to continue
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/c09e4483c765d7b6.
Report an issue: GitHub.