grpc/grpc-go · error

ClientConn's authority from transport creds %q and dial opti

Error message

ClientConn's authority from transport creds %q and dial option %q don't match

What it means

initAuthority (clientconn.go:1953-1959) reads the server name from transport credentials (creds.Info().ServerName) and the value set by the WithAuthority() dial option. If BOTH are non-empty AND they differ, the channel refuses to start because the authority would be ambiguous for TLS SNI and :authority headers.

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 03255a9237)

Solutions

  1. Make the WithAuthority() value and the credentials ServerName identical.
  2. If they must differ legitimately, remove one of them — typically drop WithAuthority and rely on the creds' ServerName.
  3. Use OverrideServerName on the credentials so there is a single source of truth.

Example fix

// before
creds := credentials.NewTLS(&tls.Config{ServerName: "a.example"})
grpc.WithTransportCredentials(creds), grpc.WithAuthority("b.example")
// after
creds := credentials.NewTLS(&tls.Config{ServerName: "a.example"})
grpc.WithTransportCredentials(creds)  // authority derived from creds
Defensive patterns

Strategy: validation

Validate before calling

// Ensure authority and credential ServerName agree before constructing the channel.
func authoritiesAgree(serverName, authority string) bool {
    if serverName == "" || authority == "" { return true }
    return serverName == authority
}

Prevention

When it happens

Trigger: Combining credentials.NewTLS credsWithServerName(...) (or OverrideServerName) with grpc.WithAuthority("...") where the two strings disagree. NewClient/Dial fails before connecting.

Common situations: Setting WithAuthority for a proxy but leaving the TLS creds pointed at the real backend name; refactoring that updated one and not the other; connecting through an LB with a different authority than the cert SAN.

Related errors


AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07). Data as JSON: /api/errors/cf27f0ac6663cc87. Report an issue: GitHub.