{"record":{"id":"b10b7c6e4cd4f6af","repo":"grpc/grpc-go","slug":"grpc-the-server-has-been-stopped","errorCode":null,"errorMessage":"grpc: the server has been stopped","messagePattern":"grpc: the server has been stopped","errorType":"exception","errorClass":"ErrServerStopped","httpStatus":null,"severity":"critical","filePath":"server.go","lineNumber":856,"sourceCode":"\t\tfor m, d := range srv.streams {\n\t\t\tmethods = append(methods, MethodInfo{\n\t\t\t\tName:           m,\n\t\t\t\tIsClientStream: d.ClientStreams,\n\t\t\t\tIsServerStream: d.ServerStreams,\n\t\t\t})\n\t\t}\n\n\t\tret[n] = ServiceInfo{\n\t\t\tMethods:  methods,\n\t\t\tMetadata: srv.mdata,\n\t\t}\n\t}\n\treturn ret\n}\n\n// ErrServerStopped indicates that the operation is now illegal because of\n// the server being stopped.\nvar ErrServerStopped = errors.New(\"grpc: the server has been stopped\")\n\ntype listenSocket struct {\n\tnet.Listener\n\tchannelz *channelz.Socket\n}\n\nfunc (l *listenSocket) Close() error {\n\terr := l.Listener.Close()\n\tchannelz.RemoveEntry(l.channelz.ID)\n\tchannelz.Info(logger, l.channelz, \"ListenSocket deleted\")\n\treturn err\n}\n\n// Serve accepts incoming connections on the listener lis, creating a new\n// ServerTransport and service goroutine for each. The service goroutines\n// read gRPC requests and then call the registered handlers to reply to them.\n// Serve returns when lis.Accept fails with fatal errors.  lis will be closed when\n// this method returns.","sourceCodeStart":838,"sourceCodeEnd":874,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/server.go#L838-L874","documentation":"Sentinel error ErrServerStopped (server.go:856) returned by Server.Serve (and xds.GRPCServer.Serve at xds/server.go:183) when Serve() is invoked after the server has already been stopped via Stop(), GracefulStop(), or Close(). It signals an illegal lifecycle transition: a gRPC Server is single-use; once stopped its internal listener map (s.lis) is nilled and its quit event has fired, so it cannot accept connections again.","triggerScenarios":"Calling server.Serve(lis) a second time, or calling Serve(lis2) on a different listener after Stop()/GracefulStop() returned; in xds, calling GRPCServer.Serve after GRPCServer.Close fired the quit event (checked via s.quit.HasFired() at xds/server.go:182).","commonSituations":"Restart loops that reuse the same *grpc.Server; HTTP/gRPC muxing where the server is stopped on SIGHUP then Serve is re-entered; tests that defer Stop() then call Serve again; xds.GRPCServer that was Close()d on error being reused.","solutions":["Do not reuse a stopped *grpc.Server; construct a fresh grpc.NewServer() / xds.NewGRPCServer() before calling Serve again.","Guard Serve with a single-flight/once flag so Stop()/GracefulStop() and Serve cannot race, and so Serve is only called once per server instance.","If you need live reload, keep the existing Server running and rebuild a new listener+server, swapping them atomically, instead of restarting the same Server.","Check the returned error with errors.Is(err, grpc.ErrServerStopped) to distinguish this from listener errors and surface a clear lifecycle message."],"exampleFix":"// before\nsrv := grpc.NewServer()\nsrv.Stop()\nsrv.Serve(lis) // returns grpc.ErrServerStopped\n\n// after\nsrv := grpc.NewServer()\nsrv.Stop()\nsrv = grpc.NewServer() // build a fresh server\nregister(srv)\ngo srv.Serve(lis)","handlingStrategy":"validation","validationCode":"// A grpc.Server is single-use. Validate lifecycle before calling Serve.\nif serverStopped {\n    srv = grpc.NewServer()\n    registerHandlers(srv)\n}\n// Then:\nif err := srv.Serve(lis); err != nil {\n    if errors.Is(err, grpc.ErrServerStopped) {\n        // lifecycle bug: Serve called after Stop/GracefulStop\n    }\n}","typeGuard":null,"tryCatchPattern":"if err := srv.Serve(lis); err != nil {\n    if errors.Is(err, grpc.ErrServerStopped) {\n        // Build a new server instead of reusing the stopped one.\n    } else {\n        // ordinary Serve error (listener failure)\n    }\n}","preventionTips":["Never call Serve twice on the same *grpc.Server; create a fresh server for each restart.","Use a sync.Once or explicit 'serving' flag to prevent Stop/GracefulStop racing with Serve.","Treat a stopped server as terminal; rebuild listener + server together on reload."],"tags":["grpc","server","lifecycle","go"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}