grpc/grpc-java · error · CertificateException
Peer certificate SAN check failed
Error message
Peer certificate SAN check failed
What it means
Thrown by XdsX509TrustManager.verifySubjectAltNameInLeaf when the peer's leaf certificate has no Subject Alternative Name extension at all (getSubjectAlternativeNames() returns null or an empty collection), while verify_subject_alt_name matchers are configured in the xDS cert context. The library mirrors Envoy's ContextImpl.verifySubjectAltName logic: when SAN matchers are configured, a peer cert without any SANs cannot be authenticated, so the TLS handshake fails with this CertificateException.
Source
Thrown at xds/src/main/java/io/grpc/xds/internal/security/trust/XdsX509TrustManager.java:201
if (altNameType == null) {
throw new CertificateParsingException("Invalid SAN entry: null altNameType");
}
switch (altNameType) {
case ALT_DNS_NAME:
case ALT_URI_NAME:
case ALT_IPA_NAME:
return verifyDnsNameInSanList((String) entry.get(1), verifySanList);
default:
return false;
}
}
// logic from Envoy::Extensions::TransportSockets::Tls::ContextImpl::verifySubjectAltName
private static void verifySubjectAltNameInLeaf(
X509Certificate cert, List<StringMatcher> verifyList) throws CertificateException {
Collection<List<?>> names = cert.getSubjectAlternativeNames();
if (names == null || names.isEmpty()) {
throw new CertificateException("Peer certificate SAN check failed");
}
for (List<?> name : names) {
if (verifyOneSanInList(name, verifyList)) {
return;
}
}
// at this point there's no match
throw new CertificateException("Peer certificate SAN check failed");
}
/**
* Verifies SANs in the peer cert chain against verify_subject_alt_name in the certContext.
* This is called from various check*Trusted methods.
*/
@VisibleForTesting
void verifySubjectAltNameInChain(X509Certificate[] peerCertChain,
List<StringMatcher> verifyList) throws CertificateException {
if (certContext == null) {View on GitHub (pinned to 64daddc1f3)
Solutions
- Reissue the peer certificate so it includes at least one Subject Alternative Name (DNS, URI, or IP) matching the configured verify_subject_alt_name matchers
- If SAN verification is not required, remove the match_subject_alt_names / verify_subject_alt_name entries from the xDS cert context so verifyList is empty
- Verify the correct leaf cert is being presented (peerCertChain[0]) — check the peer's serving/admin cert selection
- Inspect the peer cert with `openssl x509 -in cert.pem -text` and confirm an 'X509v3 Subject Alternative Name' section exists
Example fix
// before: certificate generated with only CN generate-cert --cn mysvc.example.com // after: include SAN (openssl example) openssl req -new -x509 -subj "/CN=mysvc.example.com" \ -addext "subjectAltName=DNS:mysvc.example.com"
Defensive patterns
Strategy: validation
Validate before calling
// Pre-check a peer cert before handshake/config acceptance
static boolean hasSanEntries(X509Certificate cert) throws CertificateParsingException {
Collection<List<?>> sans = cert.getSubjectAlternativeNames();
return sans != null && !sans.isEmpty();
} Type guard
static boolean hasSans(X509Certificate c) {
try {
Collection<List<?>> s = c.getSubjectAlternativeNames();
return s != null && !s.isEmpty();
} catch (CertificateParsingException e) {
return false;
}
} Try / catch
try {
tlsHandshake();
} catch (SSLHandshakeException e) {
if (e.getCause() instanceof CertificateException
&& e.getCause().getMessage().contains("SAN check failed")) {
log.error("Peer cert has no SANs matching configured matchers; reissue cert or fix match_subject_alt_names");
}
throw e;
} Prevention
- Always generate certs with subjectAltName; never rely on the deprecated CN field
- Add a CI check that fails when issued certs lack SAN entries
- Keep match_subject_alt_names in sync with the certs your CA actually issues
When it happens
Trigger: During checkClientTrusted/checkServerTrusted, after the delegate trust manager passes chain validation, verifySubjectAltNameInChain is called with a non-empty match list and the leaf cert (peerCertChain[0]) exposes no SAN entries whatsoever.
Common situations: Peer certificates issued by an internal CA or tooling (e.g. old OpenSSL configs, cert-manager without SAN templates) that only use the deprecated CN field instead of SANs; mTLS between gRPC xDS services where one side was issued a legacy cert; certificates regenerated by an upgraded issuer that dropped the SAN extension.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Failed to extract SPIFFE ID from peer leaf certificate
- Spiffe Trust Map doesn't contain trust domain '%s' from peer
- Multiple URI SAN values found in the leaf cert.
- Peer certificate(s) missing
- ${validationResult.getValidationDetails()} (server-provided
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/c73758271787c117.
Report an issue: GitHub.