{"record":{"id":"d2936028ec240f83","repo":"grpc/grpc-go","slug":"grpc-credentials-bundle-must-return-non-nil-trans","errorCode":null,"errorMessage":"grpc: credentials.Bundle must return non-nil transport credentials","messagePattern":"grpc: credentials\\.Bundle must return non-nil transport credentials","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"clientconn.go","lineNumber":96,"sourceCode":"\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.\n\terrTransportCredsAndBundle = errors.New(\"grpc: credentials.Bundle may not be used with individual TransportCredentials\")\n\t// errNoTransportCredsInBundle indicated that the configured creds bundle\n\t// returned a transport credentials which was nil.\n\terrNoTransportCredsInBundle = errors.New(\"grpc: credentials.Bundle must return non-nil transport credentials\")\n\t// errTransportCredentialsMissing indicates that users want to transmit\n\t// security information (e.g., OAuth2 token) which requires secure\n\t// connection on an insecure connection.\n\terrTransportCredentialsMissing = errors.New(\"grpc: the credentials require transport level security (use grpc.WithTransportCredentials() to set)\")\n)\n\nvar (\n\tdisconnectionsMetric = expstats.RegisterInt64Count(expstats.MetricDescriptor{\n\t\tName:           \"grpc.subchannel.disconnections\",\n\t\tDescription:    \"EXPERIMENTAL. Number of times the selected subchannel becomes disconnected.\",\n\t\tUnit:           \"{disconnection}\",\n\t\tLabels:         []string{\"grpc.target\"},\n\t\tOptionalLabels: []string{\"grpc.lb.backend_service\", \"grpc.lb.locality\", \"grpc.disconnect_error\"},\n\t\tDefault:        false,\n\t})\n\tconnectionAttemptsSucceededMetric = expstats.RegisterInt64Count(expstats.MetricDescriptor{\n\t\tName:           \"grpc.subchannel.connection_attempts_succeeded\",\n\t\tDescription:    \"EXPERIMENTAL. Number of successful connection attempts.\",","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/clientconn.go#L78-L114","documentation":"Documented as thrown by convertCustomConfig when the typeURL split on '/' yields zero segments, but this code path is effectively unreachable: Go's strings.Split always returns at least one element (even for an empty string it returns [\"\"]). Therefore len(urls) == 0 after strings.Split is always false. If it were reachable, it would indicate a typeURL that is not URL-like. In practice, the empty-name case is caught earlier at converter.go:43-44 (empty loggerName) rather than here.","triggerScenarios":"Effectively unreachable under normal Go semantics. The only theoretical trigger would be a non-standard strings.Split implementation or a future refactor that changes the splitting logic. If you see this error in the wild, it indicates a code-generation anomaly or memory corruption, not a configuration mistake.","commonSituations":"Not reproducible with standard Go. If encountered, likely a symptom of a patched/modified strings package or a different code path than the one analyzed. The practical equivalent — an empty typeURL producing an empty logger name — is handled by the loggerName empty check at line 43-44.","solutions":["If you encounter this error, investigate whether the grpc-go source or strings package has been modified; under standard Go it cannot fire.","For the practical empty-typeURL problem, set the type_url to a non-empty URL-formatted string with a '/' separator (e.g., prefix/LoggerName).","Report the error as a potential bug if it occurs with unmodified grpc-go, since the guard at line 87 is dead code."],"exampleFix":"// This error is unreachable; strings.Split never returns a 0-length slice.\n// For empty-name issues, fix the type_url:\n// before:\ntypeUrl: \"\"\n// after:\ntypeUrl: \"grpc.authz.audit_logging/mylogger\"","handlingStrategy":"validation","validationCode":"// This error is unreachable (strings.Split never returns 0 elements).\n// Validate the type_url produces a non-empty name instead:\nfunc validateTypeURLName(typeURL string) error {\n    name := typeURL\n    if idx := strings.LastIndex(typeURL, \"/\"); idx >= 0 {\n        name = typeURL[idx+1:]\n    }\n    if name == \"\" {\n        return fmt.Errorf(\"type_url %q produces empty logger name\", typeURL)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Do not rely on the len(urls)==0 guard; it is dead code. Validate for empty name via LastIndex instead.","Always set type_url to a non-empty string with at least one '/' separator.","Report encounters of this error as a potential bug, since the guard is unreachable under standard Go."],"tags":["xds","rbac","grpc","audit","dead-code","type-url"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}