grpc/grpc-go · critical
ClientConn's authority from transport creds
Error message
ClientConn's authority from transport creds %q and dial option %q don't match
What it means
initAuthority determines the channel authority from three sources: WithAuthority dial option, transport credentials' ServerName, and the dial target endpoint. If both WithAuthority and the credentials specify a non-empty server name and they disagree, NewClient/Dial fails (clientconn.go:1958-1959). Mismatched authority would break TLS verification and routing, so it is rejected up front.
Solutions
- Make WithAuthority and the credentials' ServerName identical.
- Drop one of them: use only transport credentials to derive authority, or only WithAuthority, so there is no value to disagree.
- If you need to override, call OverrideServerName on the credentials to match the WithAuthority value.
Example fix
// before
creds := credentials.NewClientTLSFromCert(caPool, "server.example")
cc, err := grpc.NewClient(addr, grpc.WithTransportCredentials(creds), grpc.WithAuthority("other.example"))
// after
cc, err := grpc.NewClient(addr, grpc.WithTransportCredentials(creds)) // authority derived from creds
// or, if overriding:
creds := credentials.NewClientTLSFromCert(caPool, "override.example")
cc, err := grpc.NewClient(addr, grpc.WithTransportCredentials(creds), grpc.WithAuthority("override.example")) Defensive patterns
Strategy: validation
Validate before calling
func authoritiesAgree(creds credentials.TransportCredentials, authority string) error {
if creds == nil { return nil }
name := creds.Info().ServerName
if name != "" && authority != "" && name != authority {
return fmt.Errorf("creds ServerName %q != WithAuthority %q", name, authority)
}
return nil
} Try / catch
cc, err := grpc.NewClient(target, grpc.WithTransportCredentials(creds), grpc.WithAuthority(auth))
if err != nil && strings.Contains(err.Error(), "authority from transport creds") {
// reconcile creds.ServerName and the WithAuthority value
} Prevention
- Derive authority from a single source: either credentials or WithAuthority, not both.
- When overriding, call OverrideServerName on the credentials to match WithAuthority.
- Centralize dial-option construction so creds and authority stay in sync across targets.
When it happens
Trigger: Combining grpc.WithAuthority("a.example") with transport credentials whose ServerName is "b.example" (e.g., credentials.NewClientTLSFromFile or NewTLS with a different server name, possibly after OverrideServerName).
Common situations: Setting WithAuthority for SNI/routing while the TLS creds carry a different server name; copy-paste of dial options from another target; rotating certs/target and updating only one of the two.
Related errors
- could not get resolver for default scheme
- failed to build credentials bundle from bootstrap for
- failed to start resolver
- failed to unmarshal config
- grpc: the provided default service config is invalid
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/cf27f0ac6663cc87.
Report an issue: GitHub.
Appendix: source
Thrown at clientconn.go:1959
func (cc *ClientConn) initAuthority() error {
dopts := cc.dopts
// Historically, we had two options for users to specify the serverName or
// authority for a channel. One was through the transport credentials
// (either in its constructor, or through the OverrideServerName() method).
// The other option (for cases where WithInsecure() dial option was used)
// was to use the WithAuthority() dial option.
//
// A few things have changed since:
// - `insecure` package with an implementation of the `TransportCredentials`
// interface for the insecure case
// - WithAuthority() dial option support for secure credentials
authorityFromCreds := ""
if creds := dopts.copts.TransportCredentials; creds != nil && creds.Info().ServerName != "" {
authorityFromCreds = creds.Info().ServerName
}
authorityFromDialOption := dopts.authority
if (authorityFromCreds != "" && authorityFromDialOption != "") && authorityFromCreds != authorityFromDialOption {
return fmt.Errorf("ClientConn's authority from transport creds %q and dial option %q don't match", authorityFromCreds, authorityFromDialOption)
}
endpoint := cc.parsedTarget.Endpoint()
if authorityFromDialOption != "" {
cc.authority = authorityFromDialOption
} else if authorityFromCreds != "" {
cc.authority = authorityFromCreds
} else if auth, ok := cc.resolverBuilder.(resolver.AuthorityOverrider); ok {
cc.authority = auth.OverrideAuthority(cc.parsedTarget)
} else if strings.HasPrefix(endpoint, ":") {
cc.authority = "localhost" + encodeAuthority(endpoint)
} else {
cc.authority = encodeAuthority(endpoint)
}
return nil
}
View on GitHub (pinned to 0c51461d27)