{"record":{"id":"71941429c67d7b53","repo":"grpc/grpc-go","slug":"grpc-the-connection-is-drained","errorCode":null,"errorMessage":"grpc: the connection is drained","messagePattern":"grpc: the connection is drained","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"clientconn.go","lineNumber":72,"sourceCode":"\t_ \"google.golang.org/grpc/internal/resolver/passthrough\" // To register passthrough resolver.\n\t_ \"google.golang.org/grpc/internal/resolver/unix\"        // To register unix resolver.\n\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)\")","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/clientconn.go#L54-L90","documentation":"Thrown by buildLogger in the RBAC audit logger converter when an RBAC_AuditLoggingOptions_AuditLoggerConfig has an AuditLogger whose TypedConfig field is nil. The TypedConfig (*anypb.Any) carries the concrete logger configuration; without it, the converter cannot determine which audit logger to instantiate or how to configure it. This is a hard validation failure — the audit logger config is structurally incomplete.","triggerScenarios":"An xDS RBAC policy includes audit_logging_options with a logger_configs entry whose audit_logger.typed_config is absent. The control plane specified an audit logger by name but forgot to attach the typed configuration payload.","commonSituations":"A control plane (e.g., a custom security policy controller) that adds audit logging options but omits the inline typed config. An Istio AuthorizationPolicy with audit logging configured at the API layer but not fully translated to the xDS RBAC proto. Manual proto construction for testing that sets the logger name but not typed_config.","solutions":["Ensure every logger_configs entry in the RBAC audit_logging_options has a non-nil audit_logger.typed_config (*anypb.Any).","If using stdout audit logging, set typed_config to an Any wrapping envoy.extensions.rbac.audit_loggers.stream.v3.StdoutAuditLog.","Remove the audit_logging_options or the specific logger_configs entry if audit logging is not actually needed for that policy."],"exampleFix":"// before:\nauditLoggingOptions:\n  loggerConfigs:\n    - auditLogger:\n        name: \"envoy.rbac.audit_loggers.stdout\"\n        // typed_config missing -> error\n\n// after:\nauditLoggingOptions:\n  loggerConfigs:\n    - auditLogger:\n        name: \"envoy.rbac.audit_loggers.stdout\"\n        typedConfig:\n          \"@type\": type.googleapis.com/envoy.extensions.rbac.audit_loggers.stream.v3.StdoutAuditLog\n","handlingStrategy":"validation","validationCode":"// Validate audit logger configs before constructing the engine:\nfunc validateAuditLoggerConfigs(rbac *v3rbacpb.RBAC) error {\n    for _, opt := range rbac.GetAuditLoggingOptions().GetLoggerConfigs() {\n        if opt.GetAuditLogger().GetTypedConfig() == nil {\n            return fmt.Errorf(\"audit logger config missing TypedConfig\")\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always populate typed_config in audit logger configurations.","Use a control-plane policy validator that checks for non-nil typed_config on all audit logger entries.","Omit audit_logging_options entirely rather than including partially-specified logger configs."],"tags":["xds","rbac","grpc","audit","config"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}