{"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":"error","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/03255a9237b6eb32710f6bc4f2de9a675b99fe36/clientconn.go#L78-L114","documentation":"errNoTransportCredsInBundle (clientconn.go:94-96) is returned by validateTransportCredentials (clientconn.go:487-489) when a CredsBundle is configured but its TransportCredentials() method returns nil. A bundle MUST supply non-nil transport credentials to be usable.","triggerScenarios":"A custom credentials.Bundle implementation returns nil from TransportCredentials(), or a malformed/partial bundle is passed via WithCredentialsBundle. The check at clientconn.go:487 catches it at construction time.","commonSituations":"Hand-written or third-party CredsBundle that only implements PerRPCCredentials but leaves TransportCredentials() returning nil; using a bundle type that was only meant for a specific environment; refactor that dropped the TLS branch.","solutions":["Fix the bundle implementation so TransportCredentials() returns a valid TransportCredentials (e.g. credentials.NewTLS(tlsConf) or insecure.NewCredentials()).","If you only need per-RPC creds, use WithPerRPCCredentials(...) plus an explicit WithTransportCredentials(...) instead of a bundle.","Add a unit test asserting bundle.TransportCredentials() != nil before passing it to NewClient.","If using a Google-provided bundle, ensure it is the right constructor (e.g. oauth bundle variants) for your transport."],"exampleFix":"// before — custom bundle with nil transport creds\ntype myBundle struct{}\nfunc (b *myBundle) TransportCredentials() credentials.TransportCredentials { return nil }\n\ncc, _ := grpc.NewClient(target, grpc.WithCredentialsBundle(&myBundle{}))\n// err: grpc: credentials.Bundle must return non-nil transport credentials\n\n// after — return real transport creds\nfunc (b *myBundle) TransportCredentials() credentials.TransportCredentials {\n    return credentials.NewTLS(b.tlsConf)\n}","handlingStrategy":"type-guard","validationCode":"// Validate a bundle before handing it to NewClient\nfunc requireBundleTransport(b credentials.Bundle) error {\n    if b == nil || b.TransportCredentials() == nil {\n        return errors.New(\"bundle must provide non-nil transport credentials\")\n    }\n    return nil\n}","typeGuard":"func hasTransportCreds(b credentials.Bundle) bool {\n    return b != nil && b.TransportCredentials() != nil\n}","tryCatchPattern":"cc, err := grpc.NewClient(target, grpc.WithCredentialsBundle(b))\nif err != nil && strings.Contains(err.Error(), \"Bundle must return non-nil\") {\n    // fix the bundle impl or switch to WithTransportCredentials\n}","preventionTips":["Unit-test custom bundles: assert TransportCredentials() != nil.","Prefer WithPerRPCCredentials + WithTransportCredentials when a bundle is overkill.","Pin bundle constructor to a known-good implementation."],"tags":["security","credentials","bundle","grpc-go"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}