grpc/grpc-java · critical · CertificateException
${validationResult.getValidationDetails()} (server-provided
Error message
${validationResult.getValidationDetails()} (server-provided validation details) What it means
When the S2A validates the peer certificate chain and returns a result other than SUCCESS, S2ATrustManager.checkPeerTrusted() throws a CertificateException whose message is the S2A-provided validation details. This is a genuine peer-certificate trust failure reported by the S2A during mTLS.
Source
Thrown at s2a/src/main/java/io/grpc/s2a/internal/handshaker/S2ATrustManager.java:173
} 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
- Read getValidationDetails() in the exception message to identify the exact validation failure ( expiry, untrusted root, SAN mismatch ).
- Ensure the peer's certificate chain is valid and issued by a CA the S2A trusts.
- Update the S2A's trust-domain/root configuration if certificates were recently rotated.
- Verify both peers are configured with matching S2A trust domains.
Example fix
// before // peer cert expired -> S2A rejects // after // renew peer certificate / propagate new roots to S2A trust config s2a.updateTrustBundle(newRoots);
Defensive patterns
Strategy: try-catch
Validate before calling
// check peer cert basics before the handshake
for (X509Certificate cert : peerChain) {
cert.checkValidity(); // fails fast on expired/not-yet-valid certs
} Try / catch
try {
trustManager.checkClientTrusted(chain, authType);
} catch (CertificateException e) {
// message carries S2A validation details ( expired, untrusted root, SAN mismatch )
logger.warning("Peer cert rejected by S2A: " + e.getMessage());
throw e; // do not bypass trust validation
} Prevention
- Keep peer certificates renewed and chains complete.
- Propagate root CA rotations to the S2A trust configuration promptly.
- Ensure trust domains on both peers are configured consistently.
- Never catch and ignore this exception — it signals a real trust failure.
When it happens
Trigger: checkClientTrusted/checkServerTrusted receives ValidatePeerCertificateChainResp whose ValidationResult != SUCCESS — the peer's certificate chain failed S2A-side validation, with getValidationDetails() explaining why.
Common situations: Peer presenting a cert from an untrusted CA or expired certificate; wrong trust domain configuration on the S2A; hostname/SAN mismatch in peer identity; rotated roots not yet propagated to the S2A.
Related errors
- Failed to send request to S2A.
- Error occurred in response from S2A, error code: %d, error m
- No valid response received from S2A.
- 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/78d7c26e407cc870.
Report an issue: GitHub.