grpc/grpc-go · error
unsupported mode
Error message
unsupported mode: %v
What it means
Returned by (*creds).NewWithMode when the requested mode string is not one of the three internal constants (CredsBundleModeFallback, CredsBundleModeBackendFromBalancer, CredsBundleModeBalancer). This is an internal gRPC API: external callers should not pass arbitrary mode strings. The %v echoes the offending mode.
Solutions
- Stop calling NewWithMode with custom strings; use only the public constructors (NewDefaultCredentials, NewComputeEngineCredentials).
- If you must call NewWithMode, import the mode constants from google.golang.org/grpc/internal (or prefer the public bundle API) and never pass literals.
- Align gRPC versions across modules so the internal constant values are consistent.
Example fix
// before
bundle, err := c.NewWithMode("custom-mode")
// after
bundle, err := c.NewWithMode(internal.CredsBundleModeFallback) Defensive patterns
Strategy: validation
Validate before calling
// Do not construct custom mode strings; use only the public bundle constructors.
// If you must call NewWithMode, validate against the known set:
func isValidMode(m string) bool {
return m == internal.CredsBundleModeFallback ||
m == internal.CredsBundleModeBackendFromBalancer ||
m == internal.CredsBundleModeBalancer
}
if !isValidMode(mode) {
return fmt.Errorf("unsupported mode %q; use a public credentials constructor", mode)
} Try / catch
bundle, err := c.NewWithMode(mode)
if err != nil && strings.HasPrefix(err.Error(), "unsupported mode") {
log.Fatalf("internal API misuse: %v", err)
} Prevention
- Prefer NewDefaultCredentials / NewComputeEngineCredentials over manual NewWithMode calls.
- Treat NewWithMode as internal; never fuzz or expose its mode parameter.
- Keep all grpc modules at the same version so internal constants agree.
When it happens
Trigger: Calling the Bundle.NewWithMode method on a google credentials bundle with a custom or empty mode string; a version mismatch where internal mode constant values changed but a caller hardcodes a literal.
Common situations: Custom resolvers or balancer plugins that invoke NewWithMode with a mode not defined in internal/internal.go; copy-pasted code from an older gRPC version using now-renamed constants; testing harnesses that fuzz the mode parameter.
Related errors
- request info not found from context
- token file is empty
- AuthInfo is nil
- buffer size is not an exponent of two
- cannot send secure credentials on an insecure connection
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/bbcf7179fe45c777.
Report an issue: GitHub.
Appendix: source
Thrown at credentials/google/google.go:146
// NewWithMode should make a copy of Bundle, and switch mode. Modifying the
// existing Bundle may cause races.
func (c *creds) NewWithMode(mode string) (credentials.Bundle, error) {
newCreds := &creds{
opts: c.opts,
mode: mode,
}
// Create transport credentials.
switch mode {
case internal.CredsBundleModeFallback:
newCreds.transportCreds = newClusterTransportCreds(newTLS(), newALTS())
case internal.CredsBundleModeBackendFromBalancer, internal.CredsBundleModeBalancer:
// Only the clients can use google default credentials, so we only need
// to create new ALTS client creds here.
newCreds.transportCreds = newALTS()
default:
return nil, fmt.Errorf("unsupported mode: %v", mode)
}
if mode == internal.CredsBundleModeFallback || mode == internal.CredsBundleModeBackendFromBalancer {
newCreds.perRPCCreds = newCreds.opts.PerRPCCreds
}
return newCreds, nil
}
// dualPerRPCCreds implements credentials.PerRPCCredentials by embedding the
// fallback PerRPCCredentials and the ALTS one. It pickes one of them based on
// the channel type.
type dualPerRPCCreds struct {
perRPCCreds credentials.PerRPCCredentials
altsPerRPCCreds credentials.PerRPCCredentials
}
func (d *dualPerRPCCreds) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {View on GitHub (pinned to 0c51461d27)