{"record":{"id":"97225e157f834de3","repo":"grpc/grpc-go","slug":"grpc-the-connection-is-closing","errorCode":null,"errorMessage":"grpc: the connection is closing","messagePattern":"grpc: the connection is closing","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"clientconn.go","lineNumber":74,"sourceCode":"\t_ \"google.golang.org/grpc/resolver/dns\"                  // To register dns resolver.\n)\n\nconst (\n\t// minimum time to give a connection to complete\n\tminConnectTimeout = 20 * time.Second\n)\n\nvar (\n\t// ErrClientConnClosing indicates that the operation is illegal because\n\t// the ClientConn is closing.\n\t//\n\t// Deprecated: this error should not be relied upon by users; use the status\n\t// code of Canceled instead.\n\tErrClientConnClosing = status.Error(codes.Canceled, \"grpc: the client connection is closing\")\n\t// errConnDrain indicates that the connection starts to be drained and does not accept any new RPCs.\n\terrConnDrain = errors.New(\"grpc: the connection is drained\")\n\t// errConnClosing indicates that the connection is closing.\n\terrConnClosing = errors.New(\"grpc: the connection is closing\")\n\t// errConnIdling indicates the connection is being closed as the channel\n\t// is moving to an idle mode due to inactivity.\n\terrConnIdling = errors.New(\"grpc: the connection is closing due to channel idleness\")\n\t// invalidDefaultServiceConfigErrPrefix is used to prefix the json parsing error for the default\n\t// service config.\n\tinvalidDefaultServiceConfigErrPrefix = \"grpc: the provided default service config is invalid\"\n\t// PickFirstBalancerName is the name of the pick_first balancer.\n\tPickFirstBalancerName = pickfirst.Name\n)\n\n// The following errors are returned from Dial and DialContext\nvar (\n\t// errNoTransportSecurity indicates that there is no transport security\n\t// being set for ClientConn. Users should either set one or explicitly\n\t// call WithInsecure DialOption to disable security.\n\terrNoTransportSecurity = errors.New(\"grpc: no transport security set (use grpc.WithTransportCredentials(insecure.NewCredentials()) explicitly or set credentials)\")\n\t// errTransportCredsAndBundle indicates that creds bundle is used together\n\t// with other individual Transport Credentials.","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/clientconn.go#L56-L92","documentation":"Internal sentinel errConnClosing (clientconn.go:73-74) surfaced when the ClientConn is being torn down or the dial context is cancelled. It is returned from exitIdleMode when cc.conns==nil (clientconn.go:394-396) and from tryAllAddrs when ctx.Err()!=nil (clientconn.go:1455-1456). The user-facing analogue is ErrClientConnClosing (status Canceled).","triggerScenarios":"ClientConn.Close() was called (or is in progress) while an RPC or connection attempt is outstanding; the dial context was cancelled before a transport was established; the channel is re-entering idle while a connection attempt races.","commonSituations":"Calling Close() then reusing the same *grpc.ClientConn; cancelling the DialContext; application shutdown racing with in-flight RPCs; defer-ordered teardown that closes the channel before pending calls return.","solutions":["Stop issuing RPCs on a ClientConn before/after Close(); treat Close as terminal — create a new ClientConn to reconnect.","If you need ordered shutdown, wait for in-flight RPCs to finish (WaitGroup/context) before Close().","When using DialContext, ensure the context outlives the dial (or pass context.Background() and rely on WithTimeout for the connect deadline).","Map Canceled status (ErrClientConnClosing) at the application layer to a clean shutdown rather than a retryable error."],"exampleFix":"// before — reuse after close\ncc, _ := grpc.NewClient(target)\ncc.Close()\nclient.SayHello(ctx, req) // -> connection is closing\n\n// after — create a fresh client to reconnect\ncc, _ := grpc.NewClient(target)\n// ... use cc ...\ncc.Close()\ncc2, _ := grpc.NewClient(target)\ndefer cc2.Close()","handlingStrategy":"validation","validationCode":"// Treat Close as terminal; do not reuse the ClientConn\nfunc dialOnce(target string) *grpc.ClientConn {\n    cc, err := grpc.NewClient(target, /* creds */)\n    if err != nil { panic(err) }\n    return cc // caller owns Close(); never use after Close()\n}","typeGuard":null,"tryCatchPattern":"if errors.Is(err, grpc.ErrClientConnClosing) || status.Code(err) == codes.Canceled {\n    // channel is shutting down; do not retry on the same ClientConn\n}","preventionTips":["Never issue RPCs after Close(); create a new ClientConn to reconnect.","Wait for in-flight RPCs (WaitGroup) before Close().","Pass a long-lived context to DialContext; cancel only for real abort."],"tags":["connection","lifecycle","close","grpc-go"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}