grpc/grpc-go · error

%v

Error message

%v

What it means

A passthrough error returned from doHandshake when the ALTS handshaker service responded with a non-OK gRPC status. The message is literally %v of resp.GetStatus().Details, so the actionable text comes from the handshaker service itself, not from this library. It means the handshaker accepted the stream but rejected the handshake payload (bad identities, incompatible protocols, authorization failure).

Source

Thrown at credentials/alts/internal/handshaker/handshaker.go:271

	}

	conn, result, err := h.doHandshake(req)
	if err != nil {
		return nil, nil, err
	}
	authInfo := authinfo.New(result)
	return conn, authInfo, nil
}

func (h *altsHandshaker) doHandshake(req *altspb.HandshakerReq) (net.Conn, *altspb.HandshakerResult, error) {
	resp, err := h.accessHandshakerService(req)
	if err != nil {
		return nil, nil, err
	}
	// Check of the returned status is an error.
	if resp.GetStatus() != nil {
		if got, want := resp.GetStatus().Code, uint32(codes.OK); got != want {
			return nil, nil, fmt.Errorf("%v", resp.GetStatus().Details)
		}
	}

	var extra []byte
	if req.GetServerStart() != nil {
		if resp.GetBytesConsumed() > uint32(len(req.GetServerStart().GetInBytes())) {
			return nil, nil, errOutOfBound
		}
		extra = req.GetServerStart().GetInBytes()[resp.GetBytesConsumed():]
	}
	result, extra, err := h.processUntilDone(resp, extra)
	if err != nil {
		return nil, nil, err
	}
	// The handshaker returns a 128 bytes key. It should be truncated based
	// on the returned record protocol.
	keyLen, ok := keyLength[result.RecordProtocol]
	if !ok {

View on GitHub (pinned to 03255a9237)

Solutions

  1. Read the inner Details string — it is the only place the real reason appears; match it to the handshaker service's documented failure modes.
  2. Verify ClientHandshakerOptions.TargetServiceAccounts matches the server's actual service account, and that IAM permits the caller.
  3. Align RPCVersions on both peers or omit them to let defaults apply.
  4. Confirm both endpoints are in a trust domain recognized by the ALTS handshaker service.

Example fix

// before: target accounts guessed
opts := &alts.ClientHandshakerOptions{
    TargetServiceAccounts: []string{"wrong@project.iam.gserviceaccount.com"},
}

// after: omit to let ALTS derive, or use the verified SA
opts := &alts.ClientHandshakerOptions{
    TargetServiceAccounts: []string{"svc@PROJECT.iam.gserviceaccount.com"},
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-validate handshaker options so the service does not reject them.
func validateClientOpts(o *handshaker.ClientHandshakerOptions) error {
    for _, sa := range o.TargetServiceAccounts {
        if !strings.HasSuffix(sa, ".iam.gserviceaccount.com") {
            return fmt.Errorf("invalid target service account: %q", sa)
        }
    }
    return nil
}

Type guard

// Narrow a returned handshaker error if it carries gRPC status.
func isHandshakerStatusErr(err error) (string, bool) {
    var s *status.Status
    // The inner details are a string; unwrap and inspect.
    if err != nil && strings.Contains(err.Error(), "status") {
        return err.Error(), true
    }
    _ = s
    return "", false
}

Try / catch

_, _, err := h.ClientHandshake(ctx)
if err != nil {
    // err.Error() is the handshaker service's own Details string; log and surface to the caller.
    // Do not retry blindly: identity/authz failures are not transient.
    return fmt.Errorf("alts handshake rejected by service: %w", err)
}

Prevention

When it happens

Trigger: The StartClientHandshakeReq/StartServerHandshakeReq was delivered to the handshaker service but resp.Status.Code != codes.OK at handshaker.go:270. Concrete causes: TargetServiceAccounts in ClientHandshakerOptions do not match any peer identity, RPCVersions are incompatible, the local/peer service account is not authorized, or the record/application protocol negotiation found no overlap.

Common situations: Misconfigured target service accounts in ClientHandshakerOptions.TargetServiceAccounts, cross-project calls without IAM authorization, version skew between two ALTS peers (one advertising RpcProtocolVersions the other rejects), or a peer presenting an identity the handshaker service does not trust.

Related errors


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