apache/shenyu · error · ShenyuException

Could not load certificate

Error message

Could not load certificate '${trustedCert}'

What it means

HttpClientProperties builds a TrustManager from the configured trusted certificates. For each trustedCert path it resolves a resource URL and parses certificates with an X.509 CertificateFactory; if reading the resource throws IOException, a ShenyuException naming the cert path is thrown during HTTP client initialization.

Solutions

  1. Verify the trustedCert path exists and is readable from the gateway process (use an absolute path or classpath: prefix as appropriate).
  2. Mount/ship the certificate file into the container/pod at the configured path.
  3. Fix file permissions so the gateway user can read the cert.
  4. Check the wrapped IOException cause for the precise reason (ENOENT vs permission vs connection for remote URLs).

Example fix

// before (application.yml)
shenyu.httpclient.ssl.trusted-cert: /etc/ssl/old/ca.pem
// after
shenyu.httpclient.ssl.trusted-cert: /etc/ssl/certs/ca-current.pem
Defensive patterns

Strategy: validation

Validate before calling

File cert = new File(trustedCertPath);
if (!cert.isFile() || !cert.canRead()) {
  throw new IllegalStateException("trustedCert not readable: " + cert.getAbsolutePath());
}

Type guard

function isReadableFile(p) {
  try { return require('fs').accessSync(p, require('fs').constants.R_OK) === undefined; }
  catch { return false; }
}

Try / catch

try {
  trustManager = buildTrustManager(trustedCertPaths);
} catch (ShenyuException e) {
  log.error("TLS trust material missing: {}", e.getMessage(), e);
  throw new IllegalStateException("Fix trustedCert path before starting gateway", e);
}

Prevention

When it happens

Trigger: shenyu.httpclient.ssl.trustedCert (or equivalent config) points to a file that cannot be opened: wrong path, not on the classpath/filesystem, unreadable permissions, or container image missing the cert file — url.openStream() raises IOException.

Common situations: Mounting certs at a different path in Docker than configured, typo in the cert path property, relative path resolved against the wrong working directory, Kubernetes secret not mounted, cert file renamed after a rotation.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of apache/shenyu@567142e072 (2026-09-12). Data as JSON: /api/errors/27698bea0e80e105. Report an issue: GitHub.

Appendix: source

Thrown at shenyu-plugin/shenyu-plugin-httpclient/src/main/java/org/apache/shenyu/plugin/httpclient/config/HttpClientProperties.java:1101

        /**
         * Get trusted x 509 certificates for trust manager x 509 certificate [].
         *
         * @return the x 509 certificate []
         */
        @SuppressWarnings("all")
        public X509Certificate[] getTrustedX509CertificatesForTrustManager() {
            try {
                CertificateFactory certificateFactory = CertificateFactory
                        .getInstance("X.509");
                List<Certificate> allCerts = new ArrayList<>();
                for (String trustedCert : ssl.getTrustedX509Certificates()) {
                    try {
                        URL url = ResourceUtils.getURL(trustedCert);
                        Collection<? extends Certificate> certs = certificateFactory
                                .generateCertificates(url.openStream());
                        allCerts.addAll(certs);
                    } catch (IOException e) {
                        throw new ShenyuException(
                                "Could not load certificate '" + trustedCert + "'", e);
                    }
                }
                return allCerts.toArray(new X509Certificate[allCerts.size()]);
            } catch (CertificateException e) {
                throw new ShenyuException("Could not load CertificateFactory X.509", e);
            }
        }
    
        /**
         * Gets key manager factory.
         *
         * @return the key manager factory
         */
        public KeyManagerFactory getKeyManagerFactory() {
            try {
                if (StringUtils.isNotEmpty(getKeyStorePath())) {
                    KeyManagerFactory keyManagerFactory = KeyManagerFactory

View on GitHub (pinned to 567142e072)