{"record":{"id":"96a6424b1d09afb4","repo":"grpc/grpc-go","slug":"xds-tls-credentials-only-support-one-mode","errorCode":null,"errorMessage":"xDS TLS credentials only support one mode","messagePattern":"xDS TLS credentials only support one mode","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/bootstrap/tlscreds/bundle.go","lineNumber":111,"sourceCode":"\treturn &bundle{\n\t\ttransportCredentials: &reloadingCreds{provider: provider},\n\t}, sync.OnceFunc(func() { provider.Close() }), nil\n}\n\nfunc (t *bundle) TransportCredentials() credentials.TransportCredentials {\n\treturn t.transportCredentials\n}\n\nfunc (t *bundle) PerRPCCredentials() credentials.PerRPCCredentials {\n\t// mTLS provides transport credentials only. There are no per-RPC\n\t// credentials.\n\treturn nil\n}\n\nfunc (t *bundle) NewWithMode(string) (credentials.Bundle, error) {\n\t// This bundle has a single mode which only uses TLS transport credentials,\n\t// so there is no legitimate case where callers would call NewWithMode.\n\treturn nil, fmt.Errorf(\"xDS TLS credentials only support one mode\")\n}\n\n// reloadingCreds is a credentials.TransportCredentials for client\n// side mTLS that reloads the server root CA certificate and the client\n// certificates from the provider on every client handshake. This is necessary\n// because the standard TLS credentials do not support reloading CA\n// certificates.\ntype reloadingCreds struct {\n\tprovider certprovider.Provider\n}\n\nfunc (c *reloadingCreds) ClientHandshake(ctx context.Context, authority string, rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) {\n\tkm, err := c.provider.KeyMaterial(ctx)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tvar config *tls.Config\n\tif km.SPIFFEBundleMap != nil {","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/internal/xds/bootstrap/tlscreds/bundle.go#L93-L129","documentation":"Returned by NewWithMode on the xDS TLS credentials bundle (bundle.go:111). The bundle intentionally implements a single TLS mode and never supports mode switching, as noted in gRFC A65. Any call to NewWithMode is treated as a programming error because the bundle's transport credentials are fixed at construction time.","triggerScenarios":"Calling bundle.NewWithMode(\"some-mode\") on the bundle returned by tlscreds.NewBundle. The method body is unconditional: it always returns this error.","commonSituations":"Code that generically iterates credentials.Bundle implementations and invokes NewWithMode (e.g. adapting a bundle meant for xDS fallback or old xdstpb-style mode-based credentials). Also seen when porting examples that assumed a multi-mode bundle.","solutions":["Do not call NewWithMode on the tlscreds bundle; build a fresh bundle via NewBundle(configJSON) for each desired configuration.","If you need two credential configurations, keep two separate *bundle instances and select between them at the call site.","Audit any code path that treats credentials.Bundle polymorphically and special-case or skip NewWithMode for this bundle."],"exampleFix":"// before\nb, _, _ := tlscreds.NewBundle(cfg)\nnewB, err := b.NewWithMode(\"mtls\") // always errors\n\n// after\nb, _, _ := tlscreds.NewBundle(cfg) // already the only mode\n// use b.TransportCredentials() directly","handlingStrategy":"validation","validationCode":"// NewWithMode is unsupported; never call it on a tlscreds bundle.\n// If you hold a credentials.Bundle and must branch:\nif _, ok := b.(*tlscreds.Bundle); ok { /* skip NewWithMode */ }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat the tlscreds bundle as single-mode; do not write code that calls NewWithMode generically.","When accepting a credentials.Bundle from callers, document that NewWithMode may be unsupported.","Add a lint test that greps for NewWithMode usages on bundles returned by tlscreds.NewBundle."],"tags":["xds","tls","credentials","mtls","configuration"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}