vitessio/vitess · warning
http server stopped: %w
Error message
http server stopped: %w
What it means
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.
Source
Thrown at go/vt/vtadmin/grpcserver/server.go:245
if !strings.HasPrefix(s.opts.MetricsEndpoint, "/") {
s.opts.MetricsEndpoint = "/" + s.opts.MetricsEndpoint
}
grpc_prometheus.Register(s.gRPCServer)
s.router.Handle(s.opts.MetricsEndpoint, promhttp.Handler())
}
// Start the servers
go func() {
err := s.gRPCServer.Serve(grpcLis)
err = fmt.Errorf("grpc server stopped: %w", err)
log.Warn(fmt.Sprint(err))
shutdown <- err
}()
go func() {
err := http.Serve(anyLis, s.router)
err = fmt.Errorf("http server stopped: %w", err)
log.Warn(fmt.Sprint(err))
shutdown <- err
}()
// Start muxing connections
go func() {
err := lmux.Serve()
err = fmt.Errorf("listener closed: %w", err)
log.Warn(fmt.Sprint(err))
shutdown <- err
}()
for service := range s.gRPCServer.GetServiceInfo() {
s.healthServer.SetServingStatus(service, healthpb.HealthCheckResponse_SERVING)
}
s.setServing(true)
log.Info(fmt.Sprintf("server %s listening on %s", s.name, s.opts.Addr))View on GitHub (pinned to 01a25a7d17)
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.
Example fix
// before
log.Warn(fmt.Sprint(err))
// after
if err != nil && !errors.Is(err, http.ErrServerClosed) {
log.Warn(fmt.Sprintf("http server stopped: %v", err))
} Defensive patterns
Strategy: try-catch
Type guard
func isExpectedHTTPStop(err error) bool {
return err == nil || errors.Is(err, http.ErrServerClosed) || errors.Is(err, net.ErrClosed)
} Try / catch
err := <-shutdownCh
if !isExpectedHTTPStop(err) {
log.Error(fmt.Sprintf("http server failed: %v", err))
} Prevention
- 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.
When it happens
Trigger: `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.
Common situations: vtadmin process shutting down (lmux closed); another shutdown path closed the shared listener first; misconfiguration where the same listener was handed to two servers.
Related errors
- grpc server stopped: %w
- listener closed: %w
- no route variable found with name %s
- %w: parsing %s at position %d
- must specify at least one keyspace_shard to delete (got %+v)
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/232fba76514fcd88.
Report an issue: GitHub.