grpc/grpc-java · error · UnsupportedOperationException

decrypt is not supported.

Error message

decrypt is not supported.

What it means

S2APrivateKeyMethod implements a private-key method for the S2A handshaker but only supports signing operations. The decrypt() method is unconditionally unsupported and always throws UnsupportedOperationException when the TLS stack attempts to offload a decryption operation to the S2A. This is a deliberate design boundary, not a transient failure.

Source

Thrown at s2a/src/main/java/io/grpc/s2a/internal/handshaker/S2APrivateKeyMethod.java:145

    }

    SessionResp resp = stub.send(reqBuilder.build());

    if (resp.hasStatus() && resp.getStatus().getCode() != 0) {
      throw new S2AConnectionException(
          String.format(
              "Error occurred in response from S2A, error code: %d, error message: \"%s\".",
              resp.getStatus().getCode(), resp.getStatus().getDetails()));
    }
    if (!resp.hasOffloadPrivateKeyOperationResp()) {
      throw new S2AConnectionException("No valid response received from S2A.");
    }
    return resp.getOffloadPrivateKeyOperationResp().getOutBytes().toByteArray();
  }

  @Override
  public byte[] decrypt(SSLEngine engine, byte[] input) {
    throw new UnsupportedOperationException("decrypt is not supported.");
  }
}

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Use an ephemeral key-exchange cipher suite ( ECDHE/DHE ) so the handshake uses signatures rather than decryption.
  2. Restrict enabled cipher suites ( e.g. via SslContextBuilder ) to exclude static RSA key exchange.
  3. If decryption offload is required, use a different private-key method implementation that supports it.

Example fix

// before
sslContextBuilder.ciphers(Arrays.asList("TLS_RSA_WITH_AES_128_GCM_SHA256"));
// after
sslContextBuilder.ciphers(Arrays.asList("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"));
Defensive patterns

Strategy: validation

Validate before calling

if (cipherSuite.startsWith("TLS_RSA_")) {
  throw new IllegalArgumentException("Static RSA key exchange unsupported with S2A offload; use ECDHE suites");
}

Try / catch

try {
  keyMethod.decrypt(engine, input);
} catch (UnsupportedOperationException e) {
  // fall back to local key or reject handshake
}

Prevention

When it happens

Trigger: Calling S2APrivateKeyMethod.decrypt(SSLEngine, byte[]) directly, or using this private-key method with a TLS cipher suite/protocol flow that requires RSA key exchange ( decryption ) instead of signature-based ( e.g. ECDHE ) handshakes.

Common situations: Configuring a server socket with S2A offload while negotiating a legacy static-RSA cipher suite; custom code invoking decrypt() on the private key method; older clients that only support static RSA key exchange connecting to an S2A-offloaded endpoint.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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