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
- Use an ephemeral key-exchange cipher suite ( ECDHE/DHE ) so the handshake uses signatures rather than decryption.
- Restrict enabled cipher suites ( e.g. via SslContextBuilder ) to exclude static RSA key exchange.
- 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
- Only enable signature-based ( ECDHE/DHE ) cipher suites with S2A offload.
- Never call decrypt() on S2APrivateKeyMethod directly; rely on sign operations.
- Document the supported operation set of the private-key method in your TLS setup code.
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
- Can't set TLS settings for ALTS
- TLS not supported in BinderServer
- This method is deprecated and marked for removal. Use the ge
- TLS not supported in ServerImplBuilder
- TLS not supported in InProcessServer
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/5fa64298647a573f.
Report an issue: GitHub.