grpc/grpc-go · error
xDS TLS credentials only support one mode
Error message
xDS TLS credentials only support one mode
What it means
The xDS TLS credentials bundle is single-mode: it always uses TLS transport credentials and does not support alternate modes. bundle.NewWithMode (bundle.go:108-111) unconditionally returns this error. Calling NewWithMode is a programming error — there is no input that makes it succeed.
Source
Thrown at internal/xds/bootstrap/tlscreds/bundle.go:111
return &bundle{
transportCredentials: &reloadingCreds{provider: provider},
}, sync.OnceFunc(func() { provider.Close() }), nil
}
func (t *bundle) TransportCredentials() credentials.TransportCredentials {
return t.transportCredentials
}
func (t *bundle) PerRPCCredentials() credentials.PerRPCCredentials {
// mTLS provides transport credentials only. There are no per-RPC
// credentials.
return nil
}
func (t *bundle) NewWithMode(string) (credentials.Bundle, error) {
// This bundle has a single mode which only uses TLS transport credentials,
// so there is no legitimate case where callers would call NewWithMode.
return nil, fmt.Errorf("xDS TLS credentials only support one mode")
}
// reloadingCreds is a credentials.TransportCredentials for client
// side mTLS that reloads the server root CA certificate and the client
// certificates from the provider on every client handshake. This is necessary
// because the standard TLS credentials do not support reloading CA
// certificates.
type reloadingCreds struct {
provider certprovider.Provider
}
func (c *reloadingCreds) ClientHandshake(ctx context.Context, authority string, rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) {
km, err := c.provider.KeyMaterial(ctx)
if err != nil {
return nil, nil, err
}
var config *tls.Config
if km.SPIFFEBundleMap != nil {View on GitHub (pinned to 03255a9237)
Solutions
- Do not call NewWithMode on the xDS TLS bundle — it is intentionally unsupported.
- Restructure calling code to skip NewWithMode for bundles that only have one mode, or guard with a type assertion.
- Use TransportCredentials() directly to obtain the TLS credentials.
Example fix
// before:
// newBundle, err := bdl.NewWithMode("mtls")
// after:
// tc := bdl.TransportCredentials()
// // use tc directly; do not call NewWithMode on xDS TLS bundles Defensive patterns
Strategy: type-guard
Type guard
// Never call NewWithMode on the xDS TLS bundle.
func supportsModes(b credentials.Bundle) bool {
// The xDS TLS bundle does not support modes; treat it as single-mode.
return false
} Try / catch
// Guard generic code that iterates modes.
if _, err := bdl.NewWithMode(name); err != nil {
if strings.Contains(err.Error(), "only support one mode") {
// expected for xDS TLS bundle; use TransportCredentials() instead
} else {
return err
}
} Prevention
- Do not call NewWithMode on bundles from tlscreds.NewBundle.
- Use TransportCredentials() to obtain the credentials directly.
- Document which credential bundles are single-mode in your integration layer.
When it happens
Trigger: User code or an integration calls NewWithMode on a bundle returned by tlscreds.NewBundle. The credentials.Bundle interface includes NewWithMode, but this implementation rejects all calls because mTLS credentials have only one mode.
Common situations: Generic code that calls NewWithMode on every credentials.Bundle as part of a mode-switching routine; porting a custom credentials bundle to xDS where mode switching was expected; a framework that probes NewWithMode during setup.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- failed to unmarshal config: %v
- failed to build credentials bundle from bootstrap for %q: %v
- spiffe: verify function could not parse input certificate: %
- spiffe: verify function has no valid input certificates
- spiffe: x509 certificate Verify failed: %v
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/96a6424b1d09afb4.
Report an issue: GitHub.