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

  1. Call trustManager.updateTrustCredentials(CertificateType.FILE_PATH, path, refreshIntervalMs) or useSystemDefaultTrustCerts() before any connection is made.
  2. 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).
  3. If you truly want no verification, explicitly call useInsecureSkipVerify() instead of leaving roots unset.
  4. 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

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


AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08). Data as JSON: /api/errors/41109f7a84abf56b. Report an issue: GitHub.