{"record":{"id":"5c6be4e3f94a0a4f","repo":"jaegertracing/jaeger","slug":"failed-to-close-http-server-w","errorCode":null,"errorMessage":"failed to close HTTP server: %w","messagePattern":"failed to close HTTP server: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"cmd/jaeger/internal/extension/jaegerquery/internal/server.go","lineNumber":512,"sourceCode":"\t})\n\treturn nil\n}\n\nfunc (s *Server) HTTPAddr() string {\n\treturn s.httpConn.Addr().String()\n}\n\nfunc (s *Server) GRPCAddr() string {\n\treturn s.grpcConn.Addr().String()\n}\n\n// Close stops HTTP, GRPC servers and closes the port listener.\nfunc (s *Server) Close() error {\n\tvar errs []error\n\n\ts.telset.Logger.Info(\"Closing HTTP server\")\n\tif err := s.httpServer.Close(); err != nil {\n\t\terrs = append(errs, fmt.Errorf(\"failed to close HTTP server: %w\", err))\n\t}\n\n\ts.telset.Logger.Info(\"Stopping gRPC server\")\n\ts.grpcServer.Stop()\n\n\ts.bgFinished.Wait()\n\n\ts.telset.Logger.Info(\"Server stopped\")\n\treturn errors.Join(errs...)\n}\n","sourceCodeStart":494,"sourceCodeEnd":523,"githubUrl":"https://github.com/jaegertracing/jaeger/blob/806f4447841ecdb60519f408b004a599d515f437/cmd/jaeger/internal/extension/jaegerquery/internal/server.go#L494-L523","documentation":"Server.Close shuts down the HTTP server, stops the gRPC server, and waits for background work, collecting any errors into a joined error. If httpServer.Close() returns non-nil — e.g. the underlying listener is already closed or in a bad state — it is wrapped as 'failed to close HTTP server' and combined with any other shutdown errors.","triggerScenarios":"Calling Server.Close() (extension shutdown / SIGTERM path) when http.Server.Close() fails, which practically only happens if the server was already closed, its listener was force-closed, or an in-flight hijacked connection causes an error return from the stdlib.","commonSituations":"Double-invocation of Close (e.g. graceful-shutdown hook plus extension teardown both calling it); a listener hijacked by a streaming/upgrade connection resisting the abrupt close; process shutdown racing with the health-check or OTLP proxy connections.","solutions":["Inspect the wrapped inner error: if it indicates the server is already closed, ensure Close is called exactly once (guard with sync.Once)","Check for hijacked/streaming connections (e.g. WebSocket upgrades through the proxy) and close/complete them before shutdown","Log and treat the remaining errors as non-fatal during shutdown — the joined error still reports all sub-system failures"],"exampleFix":"var closeOnce sync.Once\n// before: Close may be called twice and fail on the second call\nclose(s.httpServer)\n// after\ncloseOnce.Do(func() { _ = server.Close() })","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := server.Close(); err != nil {\n\t// inspect joined sub-errors individually\n\tfor _, e := range errors.Unwrap(err).([]error) {\n\t\tlog.Warn(\"shutdown sub-error\", zap.Error(e))\n\t}\n}","preventionTips":["Call Close exactly once per server instance (sync.Once guard) to avoid double-close errors","Drain or complete hijacked/streaming connections (WebSockets) before Close","Treat shutdown errors as warnings — log them but do not block process exit"],"tags":["http","shutdown","lifecycle","server"],"backgroundTag":"server-shutdown-error","analyzedSha":"806f4447841ecdb60519f408b004a599d515f437","analyzedAt":"2026-09-01T02:39:22.140Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}