grpc/grpc-java · error · CertificateException
No valid response received from S2A.
Error message
No valid response received from S2A.
What it means
If the S2A's SessionResp contains neither a status error nor a ValidatePeerCertificateChainResp, S2ATrustManager.checkPeerTrusted() throws 'No valid response received from S2A.'. The response shape is a protocol invariant; a response without the validation payload indicates a broken or incompatible S2A.
Source
Thrown at s2a/src/main/java/io/grpc/s2a/internal/handshaker/S2ATrustManager.java:167
SessionResp resp;
try {
resp = stub.send(reqBuilder.build());
} catch (IOException e) {
throw new CertificateException("Failed to send request to S2A.", e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new CertificateException("Failed to send request to S2A.", e);
}
if (resp.hasStatus() && resp.getStatus().getCode() != 0) {
throw new CertificateException(
String.format(
"Error occurred in response from S2A, error code: %d, error message: %s.",
resp.getStatus().getCode(), resp.getStatus().getDetails()));
}
if (!resp.hasValidatePeerCertificateChainResp()) {
throw new CertificateException("No valid response received from S2A.");
}
ValidatePeerCertificateChainResp validationResult = resp.getValidatePeerCertificateChainResp();
if (validationResult.getValidationResult()
!= ValidatePeerCertificateChainResp.ValidationResult.SUCCESS) {
throw new CertificateException(validationResult.getValidationDetails());
}
}
private static ImmutableList<ByteString> certificateChainToDerChain(X509Certificate[] chain)
throws CertificateEncodingException {
ImmutableList.Builder<ByteString> derChain = ImmutableList.<ByteString>builder();
for (X509Certificate certificate : chain) {
derChain.add(ByteString.copyFrom(certificate.getEncoded()));
}
return derChain.build();
}
}View on GitHub (pinned to 64daddc1f3)
Solutions
- Verify the S2A process version matches the client library's handshaker proto version.
- Confirm the address serves the actual S2A service, not another gRPC server.
- Upgrade the grpc-s2a client library and the S2A to compatible releases.
Example fix
// before
// client uses older proto than S2A binary
// after
// align versions: client handshaker proto vX with S2A vX
s2aProcess.start("s2a:vX"); // same version family as the client library Defensive patterns
Strategy: validation
Validate before calling
// verify proto version compatibility at startup
if (!handshakerProtoVersionMatches(s2aProcess.getVersion(), clientProtoVersion)) {
throw new IllegalStateException("S2A handshaker proto version mismatch");
} Try / catch
try {
resp = stub.send(req);
} catch (IOException e) {
// validate resp shape defensively before use
if (!resp.hasStatus() && !resp.hasValidatePeerCertificateChainResp()) {
throw new IllegalStateException("Malformed SessionResp from S2A");
}
} Prevention
- Keep the S2A binary and client library on the same handshaker proto version.
- Verify the configured endpoint serves the S2A service, not another gRPC server.
- Upgrade both components together when protos change.
When it happens
Trigger: checkClientTrusted/checkServerTrusted gets a SessionResp with no status and no validate_peer_certificate_chain_resp field set — e.g. the S2A answered a different request type or an incompatible proto version.
Common situations: Proto version mismatch between the client library and the S2A binary; a non-S2A gRPC server responding at the configured address; S2A bug producing a malformed response.
Related errors
- Failed to send request to S2A.
- Error occurred in response from S2A, error code: %d, error m
- ${validationResult.getValidationDetails()} (server-provided
- TLS version %d is not supported.
- Signature Algorithm %d is not supported.
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/648b976c9c553d2a.
Report an issue: GitHub.