grpc/grpc-go · error · ErrServerStopped
grpc: the server has been stopped
Error message
grpc: the server has been stopped
What it means
ErrServerStopped is a package-level sentinel (server.go:856) returned by Server.Serve when the server has already been stopped via Stop or GracefulStop, i.e. s.lis is nil. It signals the operation is now illegal because the server's lifecycle has ended. Serve also closes the passed listener before returning it.
Source
Thrown at server.go:856
for m, d := range srv.streams {
methods = append(methods, MethodInfo{
Name: m,
IsClientStream: d.ClientStreams,
IsServerStream: d.ServerStreams,
})
}
ret[n] = ServiceInfo{
Methods: methods,
Metadata: srv.mdata,
}
}
return ret
}
// ErrServerStopped indicates that the operation is now illegal because of
// the server being stopped.
var ErrServerStopped = errors.New("grpc: the server has been stopped")
type listenSocket struct {
net.Listener
channelz *channelz.Socket
}
func (l *listenSocket) Close() error {
err := l.Listener.Close()
channelz.RemoveEntry(l.channelz.ID)
channelz.Info(logger, l.channelz, "ListenSocket deleted")
return err
}
// Serve accepts incoming connections on the listener lis, creating a new
// ServerTransport and service goroutine for each. The service goroutines
// read gRPC requests and then call the registered handlers to reply to them.
// Serve returns when lis.Accept fails with fatal errors. lis will be closed when
// this method returns.View on GitHub (pinned to 03255a9237)
Solutions
- Construct a fresh grpc.NewServer() for each new Serve lifecycle; do not reuse a stopped server.
- Guard Serve with your own state flag or only call it once per server instance.
- Compare the returned error to grpc.ErrServerStopped and treat it as expected during shutdown rather than a fatal error.
- Coordinate shutdown so Serve has fully returned before you attempt any post-stop operations.
Example fix
// before srv := grpc.NewServer() srv.Serve(lis) srv.Stop() srv.Serve(lis2) // returns ErrServerStopped // after srv := grpc.NewServer() go srv.Serve(lis) // on reload: srv.GracefulStop() srv = grpc.NewServer() // new instance srv.Serve(lis2)
Defensive patterns
Strategy: try-catch
Try / catch
if err := srv.Serve(lis); err != nil {
if errors.Is(err, grpc.ErrServerStopped) {
// expected during shutdown; ignore
return
}
log.Fatalf("Serve failed: %v", err)
} Prevention
- Create a new grpc.Server for each serve lifecycle.
- Track your own started/stopped flag and avoid calling Serve after Stop.
- Treat ErrServerStopped as expected in graceful-reload code paths.
When it happens
Trigger: Calling s.Serve(newListener) after s.Stop() or s.GracefulStop() has run; a restart/reload loop that reuses a stopped Server instance instead of constructing a new one.
Common situations: Graceful restart logic that keeps the old Server; calling Serve in a goroutine that races with shutdown; integration tests that Stop then Serve again on the same Server.
Related errors
- provider instance is closed
- token file access error
- empty token_exchange_service_uri in options
- required field SubjectTokenPath is not specified
- required field SubjectTokenType is not specified
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/b10b7c6e4cd4f6af.
Report an issue: GitHub.