{"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":"validation","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/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/xds/bootstrap/tlscreds/bundle.go#L93-L129","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before:\n//   newBundle, err := bdl.NewWithMode(\"mtls\")\n// after:\n//   tc := bdl.TransportCredentials()\n//   // use tc directly; do not call NewWithMode on xDS TLS bundles","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"// Never call NewWithMode on the xDS TLS bundle.\nfunc supportsModes(b credentials.Bundle) bool {\n    // The xDS TLS bundle does not support modes; treat it as single-mode.\n    return false\n}","tryCatchPattern":"// Guard generic code that iterates modes.\nif _, err := bdl.NewWithMode(name); err != nil {\n    if strings.Contains(err.Error(), \"only support one mode\") {\n        // expected for xDS TLS bundle; use TransportCredentials() instead\n    } else {\n        return err\n    }\n}","preventionTips":["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."],"tags":["xds","tls","mtls","credentials","grpc","api-misuse"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}