{"record":{"id":"79a73044db67cfe4","repo":"grpc/grpc-go","slug":"extproc-failed-to-create-channel-to-the-external","errorCode":null,"errorMessage":"extproc: failed to create channel to the external processor server %q: %v","messagePattern":"extproc: failed to create channel to the external processor server %q: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/httpfilter/extproc/ext_proc.go","lineNumber":312,"sourceCode":"// one if it doesn't exist.\nfunc (cf *clientFilter) getOrCreateExtProcChannel(server xdsresource.GRPCServiceConfig) (*grpcsync.RefCounted[v3procservicegrpc.ExternalProcessorClient], error) {\n\t// Create the grpcServiceKey.\n\tkey := grpcServiceKey{\n\t\ttargetURI:          server.TargetURI,\n\t\tchannelCredentials: server.ChannelCredentials,\n\t\tcallCredentials:    server.CallCredentials,\n\t}\n\n\t// If the channel for the key is present in the map and its refcount is\n\t// greater than 0, increment the refcount and return the channel.\n\tif rc := cf.getProcChannel(key); rc != nil {\n\t\treturn rc, nil\n\t}\n\n\t// Create the external processor channel without holding the lock.\n\tcc, cancel, err := iextproc.CreateExtProcChannel(server)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"extproc: failed to create channel to the external processor server %q: %v\", server.TargetURI, err)\n\t}\n\n\tclient := v3procservicegrpc.NewExternalProcessorClient(cc)\n\t// Create a new refcounted client. The onZero cleanup function will remove the\n\t// client from the map and close the underlying channel.\n\tvar rc *grpcsync.RefCounted[v3procservicegrpc.ExternalProcessorClient]\n\trc = grpcsync.NewRefCounted(&client, func() {\n\t\tcf.removeProcChannel(key, rc)\n\t\tcancel()\n\t})\n\n\t// Double-check if another goroutine created and stored a channel for this\n\t// key while we were unlocked.\n\tif existing := cf.storeProcChannel(key, rc); existing != rc {\n\t\trc.Decrement()\n\t\treturn existing, nil\n\t}\n\treturn rc, nil","sourceCodeStart":294,"sourceCodeEnd":330,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/internal/xds/httpfilter/extproc/ext_proc.go#L294-L330","documentation":"Returned by getOrCreateExtProcChannel (ext_proc.go:312) when iextproc.CreateExtProcChannel fails to dial the external processor server for the given TargetURI. The interceptor cannot be built, so BuildClientInterceptor returns an error and the RPC fails before reaching the dataplane unless failure_mode_allow semantics apply at a higher layer.","triggerScenarios":"Triggered at client-interceptor build time when dialing server.TargetURI fails: DNS lookup error, TCP/TLS handshake failure, no route to host, bad authority, unsupported channel credentials, or the ext_proc server is down.","commonSituations":"Ext_proc deployment not running or scaled to zero, wrong service DNS name in the xDS config, mTLS/CA mismatch between client and ext_proc server, network policy/firewall blocking the port, or a target URI scheme the resolver does not support.","solutions":["From the client pod, verify reachability: grpcurl or nc to the ext_proc server target URI/port.","Check the ext_proc server is deployed and its Service resolves (kubectl get endpoints, nslookup).","Confirm channel credentials and CA in the grpc_service match what the ext_proc server presents.","Correct the TargetURI in the xDS grpc_service (use dns:/// or xds:/// scheme as intended) and republish.","If dial failures are transient, ensure the client retries/resends the RPC so a fresh interceptor build redials."],"exampleFix":"// before: unreachable target in xDS config\ngrpc_service { target_uri: \"ext-proc:50000\" } // wrong port / no DNS\n\n// after: correct, resolvable target\ngrpc_service { target_uri: \"dns:///ext-proc.extproc-system.svc.cluster.local:443\" }","handlingStrategy":"retry","validationCode":"// Pre-flight: dial the ext_proc target before relying on it, then close.\nfunc preflightExtProcTarget(ctx context.Context, target string) error {\n    ctx, cancel := context.WithTimeout(ctx, 3*time.Second)\n    defer cancel()\n    cc, err := grpc.DialContext(ctx, target, grpc.WithBlock(), grpc.WithTransportCredentials(insecure.NewCredentials()))\n    if err != nil {\n        return fmt.Errorf(\"ext_proc target %q unreachable: %w\", target, err)\n    }\n    cc.Close()\n    return nil\n}","typeGuard":null,"tryCatchPattern":"// In the gRPC client: a failed BuildClientInterceptor surfaces as an RPC error.\n// Retry the RPC so the channel redials; pair with failure_mode_allow for resilience.\nfor attempt := 0; attempt < 3; attempt++ {\n    err := conn.Invoke(ctx, method, req, resp)\n    if err == nil { break }\n    st, _ := status.FromError(err)\n    if st.Code() != codes.Internal || !strings.Contains(st.Message(), \"failed to create channel\") {\n        break\n    }\n    time.Sleep(backoff(attempt))\n}","preventionTips":["Run a readiness/liveness probe against the ext_proc server in the same namespace.","Verify DNS and network policies from the client pod to the ext_proc target before enabling the filter.","Match the grpc_service credentials/CA to the ext_proc server's presented identity.","Use a stable Service DNS name (dns:///ext-proc.ns.svc:443) rather than a pod IP."],"tags":["grpc","xds","extproc","envoy","network","dial","tls"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}