grpc/grpc-go · error

server-side RPC versions are not compatible with this client

Error message

server-side RPC versions are not compatible with this client, local versions: %v, peer versions: %v

What it means

In the ALTS client handshake (alts.go:210-212), after a successful TLS-like handshake the client compares its negotiated RPC protocol versions against the peer's via checkRPCVersions. If the [min,max] version windows don't overlap, the secure connection is rejected. This is an ALTS (Google's GCP transport security) compatibility check.

Source

Thrown at credentials/alts/alts.go:212

	}
	opts.BoundAccessToken = g.boundAccessToken
	chs, err := handshaker.NewClientHandshaker(ctx, hsConn, rawConn, opts)
	if err != nil {
		return nil, nil, err
	}
	// Close the handshaker since we have obtained a connection.
	defer chs.Close()
	secConn, authInfo, err := chs.ClientHandshake(ctx)
	if err != nil {
		return nil, nil, err
	}
	altsAuthInfo, ok := authInfo.(AuthInfo)
	if !ok {
		return nil, nil, errors.New("client-side auth info is not of type alts.AuthInfo")
	}
	match, _ := checkRPCVersions(opts.RPCVersions, altsAuthInfo.PeerRPCVersions())
	if !match {
		return nil, nil, fmt.Errorf("server-side RPC versions are not compatible with this client, local versions: %v, peer versions: %v", opts.RPCVersions, altsAuthInfo.PeerRPCVersions())
	}
	return secConn, authInfo, nil
}

// ServerHandshake implements the server side ALTS handshaker.
func (g *altsTC) ServerHandshake(rawConn net.Conn) (_ net.Conn, _ credentials.AuthInfo, err error) {
	if !vmOnGCP {
		return nil, nil, ErrUntrustedPlatform
	}
	// Connecting to ALTS handshaker service.
	hsConn, err := service.Dial(g.hsAddress)
	if err != nil {
		return nil, nil, err
	}
	// Do not close hsConn since it's shared with other handshakes.

	ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
	defer cancel()

View on GitHub (pinned to 03255a9237)

Solutions

  1. Align client and server gRPC (and ALTS) versions so their RPC version windows overlap.
  2. If ALTS isn't required, switch both sides to TLS credentials or insecure for testing.
  3. Run ALTS only on GCP where the handshaker service negotiates a compatible version.

Example fix

// before
creds, _ := alts.NewClientCreds(alts.ClientHandshakerOptions{...})
grpc.WithTransportCredentials(creds)  // against mismatched ALTS server
// after
creds := credentials.NewTLS(&tls.Config{ServerName: "svc.example"})
grpc.WithTransportCredentials(creds)
Defensive patterns

Strategy: try-catch

Try / catch

secConn, _, err := creds.ClientHandshake(ctx, authority, rawConn)
if err != nil {
    if strings.Contains(err.Error(), "RPC versions are not compatible") {
        log.Printf("ALTS version mismatch with peer; align gRPC versions")
    }
    return err
}

Prevention

When it happens

Trigger: Using credentials/alts client-side to talk to an ALTS server whose RPC protocol version range doesn't intersect the client's compiled-in range (maxRPCVersion/minRPCVersion in alts.go). Happens across version-skewed gRPC builds.

Common situations: Client and server built from gRPC versions with different ALTS protocol versions; a non-GCP peer pretending to support ALTS; an old server that predates a protocol bump.

Related errors


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