grpc/grpc-java · critical · CertificateException
No trust roots configured
Error message
No trust roots configured
What it means
checkTrusted refuses to verify when this.delegateManager is null and verification is not INSECURELY_SKIP_ALL_VERIFICATION: there are no trust roots loaded to validate the chain against, so it throws CertificateException("No trust roots configured"). This means the manager was used before (or without) configuring trust credentials.
Source
Thrown at util/src/main/java/io/grpc/util/AdvancedTlsX509TrustManager.java:165
"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);
} else {
if (!(socket instanceof SSLSocket)) {
throw new CertificateException("socket is not a type of SSLSocket");
}
SSLSocket sslSocket = (SSLSocket)socket;
SSLParameters sslParams = sslSocket.getSSLParameters();
sslParams.setEndpointIdentificationAlgorithm(algorithm);
sslSocket.setSSLParameters(sslParams);
currentDelegateManager.checkServerTrusted(chain, authType, sslSocket);View on GitHub (pinned to 64daddc1f3)
Solutions
- Call trustManager.updateTrustCredentials(CertificateType.FILE_PATH, path, refreshIntervalMs) or useSystemDefaultTrustCerts() before any connection is made.
- Check the return/exception of updateTrustCredentials — if the initial load fails, delegateManager stays null; fix the underlying load error (missing file, bad password, no extended trust manager).
- If you truly want no verification, explicitly call useInsecureSkipVerify() instead of leaving roots unset.
- Await/wait for the initial trust configuration to complete (or perform it synchronously) before starting the gRPC channel.
Example fix
// before AdvancedTlsX509TrustManager tm = new AdvancedTlsX509TrustManager(Verification.CERTIFICATE_AND_HOST_NAME_VERIFICATION); SslContext ctx = GrpcSslContexts.forClient().trustManager(tm).build(); // after AdvancedTlsX509TrustManager tm = new AdvancedTlsX509TrustManager(Verification.CERTIFICATE_AND_HOST_NAME_VERIFICATION); tm.updateTrustCredentials(CertificateType.FILE_PATH, "/path/to/ca.pem", 60000); SslContext ctx = GrpcSslContexts.forClient().trustManager(tm).build();
Defensive patterns
Strategy: validation
Validate before calling
// Configure trust roots before building the SslContext
trustManager.updateTrustCredentials(CertificateType.FILE_PATH, "/path/to/ca.pem", 60000);
if (!trustManager.isShutdown() /* roots configured implicitly */) { /* proceed */ }
// or defensively:
try {
trustManager.checkServerTrusted(new X509Certificate[]{placeholderCert}, "TLS", sslEngine);
} catch (CertificateException e) {
if (e.getMessage().equals("No trust roots configured")) {
throw new IllegalStateException("Call updateTrustCredentials or useSystemDefaultTrustCerts before connecting");
}
} Try / catch
try {
channel = grpcManagedChannel(...);
stub.call(...);
} catch (javax.net.ssl.SSLHandshakeException e) {
if (e.getCause() != null && String.valueOf(e.getCause().getMessage()).contains("No trust roots configured")) {
throw new IllegalStateException("Trust roots not configured on AdvancedTlsX509TrustManager", e);
}
throw e;
} Prevention
- Always call updateTrustCredentials or useSystemDefaultTrustCerts immediately after constructing the manager, before opening channels.
- Check the CA file path/permissions in your environment (config maps, containers) so the initial load cannot silently fail.
- If skipping verification is intentional, call useInsecureSkipVerify() explicitly and never ship that in production.
- Log failures from updateTrustCredentials instead of swallowing them; delegateManager remains null if the initial load throws.
- Perform the initial trust-credential load synchronously before starting refresh scheduling.
When it happens
Trigger: Performing a TLS verification via checkClientTrusted/checkServerTrusted before calling updateTrustCredentials(...) or useSystemDefaultTrustCerts(), or after those calls failed/were skipped, leaving delegateManager null.
Common situations: Forgetting the updateTrustCredentials/useSystemDefaultTrustCerts call during setup; a background refresh thread failed so the initial load never completed; updateTrustCredentials scheduled for future refresh but verification attempted immediately before the first call; system-default loading threw (see related delegate error) and the failure was swallowed.
Understand the failure class
Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.
Related errors
- Response from S2A server does NOT contain ClientTlsConfigura
- Want certificate verification but got null or empty certific
- Can't set TLS settings for ALTS
- A key manager is required
- TLS not supported in BinderServer
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/41109f7a84abf56b.
Report an issue: GitHub.