{"record":{"id":"232fba76514fcd88","repo":"vitessio/vitess","slug":"http-server-stopped-w","errorCode":null,"errorMessage":"http server stopped: %w","messagePattern":"http server stopped: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"go/vt/vtadmin/grpcserver/server.go","lineNumber":245,"sourceCode":"\t\tif !strings.HasPrefix(s.opts.MetricsEndpoint, \"/\") {\n\t\t\ts.opts.MetricsEndpoint = \"/\" + s.opts.MetricsEndpoint\n\t\t}\n\n\t\tgrpc_prometheus.Register(s.gRPCServer)\n\t\ts.router.Handle(s.opts.MetricsEndpoint, promhttp.Handler())\n\t}\n\n\t// Start the servers\n\tgo func() {\n\t\terr := s.gRPCServer.Serve(grpcLis)\n\t\terr = fmt.Errorf(\"grpc server stopped: %w\", err)\n\t\tlog.Warn(fmt.Sprint(err))\n\t\tshutdown <- err\n\t}()\n\n\tgo func() {\n\t\terr := http.Serve(anyLis, s.router)\n\t\terr = fmt.Errorf(\"http server stopped: %w\", err)\n\t\tlog.Warn(fmt.Sprint(err))\n\t\tshutdown <- err\n\t}()\n\n\t// Start muxing connections\n\tgo func() {\n\t\terr := lmux.Serve()\n\t\terr = fmt.Errorf(\"listener closed: %w\", err)\n\t\tlog.Warn(fmt.Sprint(err))\n\t\tshutdown <- err\n\t}()\n\n\tfor service := range s.gRPCServer.GetServiceInfo() {\n\t\ts.healthServer.SetServingStatus(service, healthpb.HealthCheckResponse_SERVING)\n\t}\n\n\ts.setServing(true)\n\tlog.Info(fmt.Sprintf(\"server %s listening on %s\", s.name, s.opts.Addr))","sourceCodeStart":227,"sourceCodeEnd":263,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtadmin/grpcserver/server.go#L227-L263","documentation":"vtadmin runs an HTTP server on a multiplexed listener alongside gRPC; this error wraps whatever error `http.Serve` returns when that HTTP server stops. The wrapped error is logged as a warning and pushed to the shutdown channel to tear down vtadmin. Like the gRPC counterpart, it fires during normal graceful shutdown, so its presence alone is not a failure.","triggerScenarios":"`http.Serve(anyLis, s.router)` returns: the muxed listener is closed, http.Server is already serving on that listener, or the listener reports an accept error.","commonSituations":"vtadmin process shutting down (lmux closed); another shutdown path closed the shared listener first; misconfiguration where the same listener was handed to two servers.","solutions":["Inspect the wrapped error to distinguish expected shutdown from a real accept failure.","If at shutdown, treat as expected and filter http.ErrServerClosed in logs.","Ensure the muxed listener (lmux/anyLis) is closed exactly once, by vtadmin's Close path only.","Check for duplicate Serve calls on the same listener."],"exampleFix":"// before\nlog.Warn(fmt.Sprint(err))\n// after\nif err != nil && !errors.Is(err, http.ErrServerClosed) {\n\tlog.Warn(fmt.Sprintf(\"http server stopped: %v\", err))\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"func isExpectedHTTPStop(err error) bool {\n\treturn err == nil || errors.Is(err, http.ErrServerClosed) || errors.Is(err, net.ErrClosed)\n}","tryCatchPattern":"err := <-shutdownCh\nif !isExpectedHTTPStop(err) {\n\tlog.Error(fmt.Sprintf(\"http server failed: %v\", err))\n}","preventionTips":["Let vtadmin's Close() own listener lifecycle; never close the shared muxed listener elsewhere.","Use net/http/httputil or lmux correctly — never hand the same listener to two Serve calls.","Check port availability before startup to avoid early accept failures."],"tags":["http","server-lifecycle","vtadmin"],"backgroundTag":"http-server-stopped","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}