grpc/grpc-java · error · IllegalArgumentException
Want certificate verification but got null or empty certific
Error message
Want certificate verification but got null or empty certificates
What it means
checkTrusted validates the certificate chain only when it is non-null and non-empty; a null or empty chain is treated as a caller bug, not a certificate problem, so it throws IllegalArgumentException. If the caller intended to skip peer verification it should configure the manager accordingly rather than pass an empty chain.
Source
Thrown at util/src/main/java/io/grpc/util/AdvancedTlsX509TrustManager.java:156
// If found, use that as the delegate trust manager.
for (TrustManager tm : tms) {
if (tm instanceof X509ExtendedTrustManager) {
delegateManager = (X509ExtendedTrustManager) tm;
break;
}
}
if (delegateManager == null) {
throw new CertificateException(
"Failed to find X509ExtendedTrustManager with default TrustManager algorithm "
+ TrustManagerFactory.getDefaultAlgorithm());
}
return delegateManager;
}
private void checkTrusted(X509Certificate[] chain, String authType, SSLEngine sslEngine,
Socket socket, boolean checkingServer) throws CertificateException {
if (chain == null || chain.length == 0) {
throw new IllegalArgumentException(
"Want certificate verification but got null or empty certificates");
}
if (sslEngine == null && socket == null) {
throw new CertificateException(NOT_ENOUGH_INFO_MESSAGE);
}
if (this.verification != Verification.INSECURELY_SKIP_ALL_VERIFICATION) {
X509ExtendedTrustManager currentDelegateManager = this.delegateManager;
if (currentDelegateManager == null) {
throw new CertificateException("No trust roots configured");
}
if (checkingServer) {
String algorithm = this.verification == Verification.CERTIFICATE_AND_HOST_NAME_VERIFICATION
? "HTTPS" : "";
if (sslEngine != null) {
SSLParameters sslParams = sslEngine.getSSLParameters();
sslParams.setEndpointIdentificationAlgorithm(algorithm);
sslEngine.setSSLParameters(sslParams);
currentDelegateManager.checkServerTrusted(chain, authType, sslEngine);View on GitHub (pinned to 64daddc1f3)
Solutions
- Pass a non-empty X509Certificate[] chain obtained from the peer (e.g., sslEngine.getSession().getPeerCertificates()).
- If you intentionally want to skip verification, configure Verification.INSECURELY_SKIP_ALL_VERIFICATION via useInsecureSkipVerify() instead of passing an empty chain.
- Check that the peer is actually presenting a certificate (client certs require setNeedClientAuth on server side).
- Guard the call: only invoke checkTrusted paths when the session has peer certificates.
Example fix
// before
trustManager.checkServerTrusted(new X509Certificate[0], "TLS", engine);
// after
X509Certificate[] chain = (X509Certificate[]) engine.getSession().getPeerCertificates();
if (chain != null && chain.length > 0) {
trustManager.checkServerTrusted(chain, "TLS", engine);
} Defensive patterns
Strategy: validation
Validate before calling
if (chain == null || chain.length == 0) {
throw new IllegalArgumentException("Peer presented no certificates; cannot verify");
}
trustManager.checkServerTrusted(chain, authType, sslEngine); Type guard
static boolean hasCertificates(X509Certificate[] chain) {
return chain != null && chain.length > 0;
} Try / catch
try {
trustManager.checkServerTrusted(chain, authType, sslEngine);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("null or empty certificates")) {
throw new CertificateException("Peer provided no certificate chain", e);
}
throw e;
} Prevention
- Obtain the chain from sslEngine.getSession().getPeerCertificates() and check it is non-empty before verifying.
- Enable requireClientAuth/peer certificate demand so anonymous cipher suites (empty chains) are rejected at handshake.
- If verification should be skipped, use useInsecureSkipVerify() rather than empty chains.
- Guard against TLS-terminating proxies stripping the peer chain.
When it happens
Trigger: Calling checkClientTrusted or checkServerTrusted (any overload) with chain == null or chain.length == 0 — e.g., an upstream handshake passed no peer certificates, or a test harness passed an empty array.
Common situations: Tests constructing empty X509Certificate[] arrays; integration with an SSL layer that surfaced no peer certificates (anonymous cipher suites, misconfigured keystore); proxy termination stripping the peer chain; mistakenly calling verify with no certs fetched from a session.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- No trust roots configured
- Can't set TLS settings for ALTS
- A key manager is required
- Refresh interval must be greater than 0
- TLS not supported in BinderServer
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/3b53cc3c6c4f5f82.
Report an issue: GitHub.