grpc/grpc-java · error · GeneralSecurityException

Handshaker service error: ${status.getDetails()}

Error message

Handshaker service error: ${status.getDetails()}

What it means

AltsHandshakerClient.handleResponse() checks the status code embedded in each HandshakerResp returned by the ALTS handshaker service. Any non-OK status (e.g. INTERNAL, INVALID_ARGUMENT, UNAUTHENTICATED) aborts the handshake: the client logs the details, closes the stream, and throws GeneralSecurityException carrying the service's details string.

Source

Thrown at alts/src/main/java/io/grpc/alts/internal/AltsHandshakerClient.java:162

    byte[] key = new byte[KEY_LENGTH];
    result.getKeyData().substring(0, KEY_LENGTH).copyTo(key, 0);
    return key;
  }

  /**
   * Parses a handshake response, setting the status, result, and closing the handshaker, as needed.
   */
  private void handleResponse(HandshakerResp resp) throws GeneralSecurityException {
    status = resp.getStatus();
    if (resp.hasResult()) {
      result = resp.getResult();
      close();
    }
    if (status.getCode() != Status.Code.OK.value()) {
      String error = "Handshaker service error: " + status.getDetails();
      logger.log(ChannelLogLevel.DEBUG, error);
      close();
      throw new GeneralSecurityException(error);
    }
  }

  /**
   * Starts a client handshake. A GeneralSecurityException is thrown if the handshaker service is
   * interrupted or fails. Note that isFinished() must be false before this function is called.
   *
   * @return the frame to give to the peer.
   * @throws GeneralSecurityException or IllegalStateException
   */
  public ByteBuffer startClientHandshake() throws GeneralSecurityException {
    Preconditions.checkState(!isFinished(), "Handshake has already finished.");
    HandshakerReq.Builder req = HandshakerReq.newBuilder();
    setStartClientFields(req);
    HandshakerResp resp;
    try {
      logger.log(ChannelLogLevel.DEBUG, "Send ALTS handshake request to upstream");
      resp = handshakerStub.send(req.build());

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Read status.getDetails() in the exception message — it names the service-side reason; fix the underlying identity/protocol problem
  2. Verify both peers run in an environment supporting ALTS (e.g. correct GCP service accounts and Compute Engine metadata)
  3. Confirm the handshaker service address/port is correct and the service is healthy
  4. Retry the connection; transient handshaker service errors often resolve on a new handshake

Example fix

// before
AltsChannelBuilder.forTarget(target).handshakerAddress(badAddr).build();
// after
AltsChannelBuilder.forTarget(target)
    .handshakerAddress("metadata.google.internal:8080")
    .build(); // and retry on GeneralSecurityException
Defensive patterns

Strategy: retry

Validate before calling

null

Type guard

null

Try / catch

try {
  client.startClientHandshake(next);
} catch (GeneralSecurityException e) {
  logger.warn("ALTS handshake failed: " + e.getMessage()); // includes status details
  scheduleReconnectWithBackoff();
}

Prevention

When it happens

Trigger: The remote ALTS handshaker service returns a non-OK status in a response during startClientHandshake, startServerHandshake, or next() — e.g. peer identity rejected, unsupported handshake protocol, or service-side failure.

Common situations: Mismatched peer service accounts / IAM roles for ALTS on GCP, unsupported ALTS protocol negotiated, handshaker service outage, or wrong handshaker service address configured.

Understand the failure class

Related errors


AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08). Data as JSON: /api/errors/08429b45c30792a0. Report an issue: GitHub.