grpc/grpc-go · error
grpc: credentials.Bundle may not be used with individual Tra
Error message
grpc: credentials.Bundle may not be used with individual TransportCredentials
What it means
errTransportCredsAndBundle (clientconn.go:91-93) is returned by validateTransportCredentials (clientconn.go:484-486) when BOTH WithTransportCredentials(...) and WithCredentialsBundle(...) are supplied. These are mutually exclusive ways to provide transport security.
Source
Thrown at clientconn.go:93
// errConnIdling indicates the connection is being closed as the channel
// is moving to an idle mode due to inactivity.
errConnIdling = errors.New("grpc: the connection is closing due to channel idleness")
// invalidDefaultServiceConfigErrPrefix is used to prefix the json parsing error for the default
// service config.
invalidDefaultServiceConfigErrPrefix = "grpc: the provided default service config is invalid"
// PickFirstBalancerName is the name of the pick_first balancer.
PickFirstBalancerName = pickfirst.Name
)
// The following errors are returned from Dial and DialContext
var (
// errNoTransportSecurity indicates that there is no transport security
// being set for ClientConn. Users should either set one or explicitly
// call WithInsecure DialOption to disable security.
errNoTransportSecurity = errors.New("grpc: no transport security set (use grpc.WithTransportCredentials(insecure.NewCredentials()) explicitly or set credentials)")
// errTransportCredsAndBundle indicates that creds bundle is used together
// with other individual Transport Credentials.
errTransportCredsAndBundle = errors.New("grpc: credentials.Bundle may not be used with individual TransportCredentials")
// errNoTransportCredsInBundle indicated that the configured creds bundle
// returned a transport credentials which was nil.
errNoTransportCredsInBundle = errors.New("grpc: credentials.Bundle must return non-nil transport credentials")
// errTransportCredentialsMissing indicates that users want to transmit
// security information (e.g., OAuth2 token) which requires secure
// connection on an insecure connection.
errTransportCredentialsMissing = errors.New("grpc: the credentials require transport level security (use grpc.WithTransportCredentials() to set)")
)
var (
disconnectionsMetric = expstats.RegisterInt64Count(expstats.MetricDescriptor{
Name: "grpc.subchannel.disconnections",
Description: "EXPERIMENTAL. Number of times the selected subchannel becomes disconnected.",
Unit: "{disconnection}",
Labels: []string{"grpc.target"},
OptionalLabels: []string{"grpc.lb.backend_service", "grpc.lb.locality", "grpc.disconnect_error"},
Default: false,
})View on GitHub (pinned to 03255a9237)
Solutions
- Pick ONE source of transport credentials: either WithTransportCredentials(...) or WithCredentialsBundle(...), not both.
- If you need OAuth + TLS via a bundle, use a bundle that includes transport credentials (e.g. oauth.TokenSource + TLS) and drop the standalone WithTransportCredentials.
- Otherwise keep standalone TLS WithTransportCredentials and pass the per-RPC token via WithPerRPCCredentials instead of a bundle.
- Audit your DialOptions list for duplicate/overlapping credential options.
Example fix
// before — both set
cc, err := grpc.NewClient(target,
grpc.WithTransportCredentials(credentials.NewTLS(tlsConf)),
grpc.WithCredentialsBundle(oauth.TokenSourceBundle(ctx, ts)))
// err: grpc: credentials.Bundle may not be used with individual TransportCredentials
// after — bundle provides TLS + per-RPC
cc, err := grpc.NewClient(target,
grpc.WithCredentialsBundle(oauth.TokenSourceBundle(ctx, ts))) Defensive patterns
Strategy: validation
Validate before calling
// Enforce mutual exclusivity at config-build time
func buildOpts(tc credentials.TransportCredentials, bundle credentials.Bundle) []grpc.DialOption {
if tc != nil && bundle != nil {
panic("transport creds and bundle are mutually exclusive")
}
switch {
case tc != nil: return []grpc.DialOption{grpc.WithTransportCredentials(tc)}
case bundle != nil: return []grpc.DialOption{grpc.WithCredentialsBundle(bundle)}
}
return nil
} Try / catch
cc, err := grpc.NewClient(target, opts...)
if err != nil && strings.Contains(err.Error(), "Bundle may not be used") {
// remove one of the two conflicting options and retry construction
} Prevention
- Pick exactly one credential source (transport creds OR bundle).
- For OAuth+TLS prefer a bundle that bundles transport creds.
- Review merged DialOption slices from config layers.
When it happens
Trigger: NewClient/Dial is called with both a TransportCredentials and a CredsBundle in the same option set (clientconn.go:484). gRPC cannot decide which transport credentials to use, so it rejects the config.
Common situations: Copy-pasting two examples together; mixing google.golang.org/grpc/credentials/oauth bundle with a separate tls.TransportCredentials; migrating partial config where both were left in.
Related errors
- grpc: no transport security set (use grpc.WithTransportCrede
- grpc: credentials.Bundle must return non-nil transport crede
- grpc: the credentials require transport level security (use
- AuthInfo is nil
- ALTS: untrusted platform. ALTS is only supported on GCP
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/31481c619bf4ee42.
Report an issue: GitHub.