{"record":{"id":"c09e4483c765d7b6","repo":"charmbracelet/crush","slug":"failed-to-shutdown-server-v","errorCode":null,"errorMessage":"failed to shutdown server: %v","messagePattern":"failed to shutdown server: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/cmd/server.go","lineNumber":94,"sourceCode":"\t\t\tif err != nil && !errors.Is(err, server.ErrServerClosed) {\n\t\t\t\t_ = srv.Close()\n\t\t\t\tslog.Error(\"Server error\", \"error\", err)\n\t\t\t\treturn fmt.Errorf(\"server error: %v\", err)\n\t\t\t}\n\t\t}\n\n\t\tif errors.Is(err, server.ErrServerClosed) {\n\t\t\treturn nil\n\t\t}\n\n\t\tctx, cancel := context.WithTimeout(cmd.Context(), 5*time.Second)\n\t\tdefer cancel()\n\n\t\tslog.Info(\"Shutting down...\")\n\n\t\tif err := srv.Shutdown(ctx); err != nil {\n\t\t\tslog.Error(\"Failed to shutdown server\", \"error\", err)\n\t\t\treturn fmt.Errorf(\"failed to shutdown server: %v\", err)\n\t\t}\n\n\t\treturn nil\n\t},\n}\n","sourceCodeStart":76,"sourceCodeEnd":100,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/cmd/server.go#L76-L100","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)"],"exampleFix":"// before\nctx := context.Background()\nif err := srv.Shutdown(ctx); err != nil { ... }\n// after\nctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\ndefer cancel()\nif err := srv.Shutdown(ctx); err != nil {\n    _ = srv.Close() // force close lingering connections\n    return fmt.Errorf(\"failed to shutdown server: %w\", err)\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := srv.Shutdown(ctx); err != nil {\n    if errors.Is(err, context.DeadlineExceeded) {\n        slog.Warn(\"Graceful shutdown timed out; forcing close\")\n        _ = srv.Close()\n        return nil\n    }\n    return fmt.Errorf(\"failed to shutdown server: %w\", err)\n}","preventionTips":["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"],"tags":["go","http-server","graceful-shutdown","cli"],"backgroundTag":"graceful-shutdown-timeout","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}