{"record":{"id":"136bb3b8fd1e382e","repo":"grpc/grpc-go","slug":"v-v","errorCode":null,"errorMessage":"%v: %v","messagePattern":"%v: %v","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"clientconn.go","lineNumber":326,"sourceCode":"\tif !cc.dopts.block {\n\t\treturn cc, nil\n\t}\n\n\tif cc.dopts.timeout > 0 {\n\t\tvar cancel context.CancelFunc\n\t\tctx, cancel = context.WithTimeout(ctx, cc.dopts.timeout)\n\t\tdefer cancel()\n\t}\n\tdefer func() {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\tswitch {\n\t\t\tcase ctx.Err() == err:\n\t\t\t\tconn = nil\n\t\t\tcase err == nil || !cc.dopts.returnLastError:\n\t\t\t\tconn, err = nil, ctx.Err()\n\t\t\tdefault:\n\t\t\t\tconn, err = nil, fmt.Errorf(\"%v: %v\", ctx.Err(), err)\n\t\t\t}\n\t\tdefault:\n\t\t}\n\t}()\n\n\t// A blocking dial blocks until the clientConn is ready.\n\tfor {\n\t\ts := cc.GetState()\n\t\tif s == connectivity.Idle {\n\t\t\tcc.Connect()\n\t\t}\n\t\tif s == connectivity.Ready {\n\t\t\treturn cc, nil\n\t\t} else if cc.dopts.copts.FailOnNonTempDialError && s == connectivity.TransientFailure {\n\t\t\tif err = cc.connectionError(); err != nil {\n\t\t\t\tterr, ok := err.(interface {\n\t\t\t\t\tTemporary() bool\n\t\t\t\t})","sourceCodeStart":308,"sourceCodeEnd":344,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/clientconn.go#L308-L344","documentation":"Inside DialContext's blocking wait loop, when the context expires while a connection error also exists and WithReturnConnectionError (returnLastError) is set, grpc-go combines both into \"<context error>: <connection error>\" (clientconn.go:325-326). This gives the caller both the deadline/timeout reason and the underlying transport failure.","triggerScenarios":"grpc.Dial/DialContext is called with WithBlock(), WithReturnConnectionError(), and a context that times out before the channel reaches READY, while a connection error was recorded (e.g., all subchannels failed).","commonSituations":"Short dial timeouts against an unreachable backend; TLS handshake failures combined with a tight context deadline; wrong port or firewall dropping packets so the deadline fires first.","solutions":["Read both halves of the combined error: the context side (deadline exceeded / canceled) and the connection side (the real transport failure).","Address the connection error (e.g., check host/port, TLS config, network reachability) and/or increase the context timeout.","Drop WithBlock() if you do not need to block on READY; use grpc.NewClient and handle RPC errors instead."],"exampleFix":"// before\nctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)\ndefer cancel()\ncc, err := grpc.DialContext(ctx, addr, grpc.WithBlock(), grpc.WithReturnConnectionError())\n// after: give more time and verify reachability\nctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\ndefer cancel()\ncc, err := grpc.NewClient(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"cc, err := grpc.DialContext(ctx, target, grpc.WithBlock(), grpc.WithReturnConnectionError())\nif err != nil {\n    // err may be \"<ctx error>: <conn error>\"\n    if errors.Is(err, context.DeadlineExceeded) { /* timeout */ }\n    var connErr = ccErr // capture connectionError via separate path if needed\n    _ = connErr\n}","preventionTips":["Set a realistic dial timeout for the network conditions.","Verify host/port and TLS config before blocking on Dial.","Prefer grpc.NewClient + handling RPC errors over blocking DialContext with WithReturnConnectionError."],"tags":["go","grpc","dial","timeout","connection-error"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}