Salesforce Dictionary - Free Salesforce GlossarySalesforce Dictionary
All errors
Integration

System.CalloutException: SSLHandshakeException: PKIX path building failed: unable to find valid certification path to requested target

The remote server's TLS certificate isn't trusted by Salesforce. Either the cert is self-signed, signed by a CA Salesforce doesn't trust, expired, or the cert chain is incomplete. You upload the missing cert (or its issuing CA) to the org's CA Certificates store.

Also seen asSSLHandshakeException·PKIX path building failed·unable to find valid certification path·MUTUAL_AUTHENTICATION_FAILED

An Apex callout to a partner's payment API has been working for two years. Tuesday morning, every callout starts returning System.CalloutException: SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target. The partner says they didn't change anything. The Salesforce side is up. Something quietly invalidated the trust relationship between the two systems.

What the platform is checking

When Apex makes an HTTPS callout, the Salesforce runtime opens a TLS connection to the target server. Part of the TLS handshake is the server presenting a certificate chain that proves its identity. The Salesforce JVM validates the chain by following each intermediate certificate up to a root certificate it already trusts.

The JVM ships with a default trust store containing root certificates from well-known certificate authorities (DigiCert, Let's Encrypt, GlobalSign, Entrust, and others). If the server's chain leads up to one of these trusted roots, the handshake succeeds. If the chain leads to a root the JVM doesn't trust, or if intermediate certificates are missing from the chain the server sends, validation fails with PKIX path building errors.

The unable to find valid certification path to requested target message means one of three things. The server stopped sending a complete chain (the server admin reconfigured and forgot the intermediate cert). The server's certificate was reissued by a CA whose root isn't in the Salesforce trust store. Or, less commonly, the server uses a self-signed or private-CA certificate that Salesforce doesn't recognize.

The failure surfaces at runtime, not at deploy time. The Apex code itself is fine. The Remote Site Setting or Named Credential pointing to the endpoint is fine. The fault is at the TLS layer; the connection never reaches the application layer.

The broken example

A typical Apex callout that started failing:

public class PaymentClient {
    public static HttpResponse charge(Decimal amount, String cardToken) {
        Http http = new Http();
        HttpRequest req = new HttpRequest();
        req.setEndpoint('callout:Payment_API/v1/charges');
        req.setMethod('POST');
        req.setHeader('Content-Type', 'application/json');
        req.setBody(JSON.serialize(new Map<String, Object>{
            'amount' => amount,
            'token' => cardToken
        }));
        return http.send(req);
    }
}

The callout used to work. Now http.send(req) throws SSLHandshakeException before the request reaches the server. No request log appears on the partner's side; the connection never completed the handshake.

A second shape: a brand-new integration to a private API hosted on infrastructure with a self-signed certificate. The first deploy works in a sandbox where the team uploaded the cert into the trust store; the same code fails in production because nobody uploaded the cert to production's trust store.

A third shape: a partner's certificate expired and was reissued by a new CA. The old CA was in the JVM's default trust store; the new one isn't. Every endpoint signed by the new CA started failing on the day the partner cut over.

The fix, three paths

Have the server send the full chain. The most common cause is the server sending only its leaf certificate without the intermediate certificates. The browser handles missing intermediates by fetching them via AIA (Authority Information Access), but most JVM trust validation does not. Tell the partner to configure their server to send the complete certificate chain (leaf + intermediates) in the TLS response.

Tools like openssl s_client -showcerts -connect host:443 show exactly which certificates the server is sending. If only the leaf is returned, the chain is incomplete. The partner needs to fix their server config (Nginx, Apache, AWS ALB, Cloudflare all have a setting for this).

Upload the missing certificate to Salesforce. If the chain is intentionally going up to a non-default root (a private CA, an internal corporate CA, a brand-new CA Salesforce hasn't added yet), upload that CA's certificate to Salesforce's Certificate and Key Management.

Setup, Certificate and Key Management, Import from Keystore. Upload the public certificate (CRT or PEM format). The certificate becomes available in the trust store for Apex callouts.

Use a mutual-TLS Named Credential with a certificate-based identity. For partners that require mutual TLS (client certificate authentication), the Salesforce side needs to present a certificate too. Configure a Named Credential with a certificate selected from the Certificate and Key Management store. The Named Credential handles both server validation and client presentation.

The fixed example

Once the server sends the full chain, the callout works again. The Apex code doesn't change. Verify with openssl:

openssl s_client -showcerts -connect payment-api.example.com:443 < /dev/null 2>&1 | grep -E '^(s:|i:)'

The output should show multiple certificates in order: the leaf (the server's own cert), one or more intermediates, and possibly the root. If only the leaf appears, the chain is incomplete and the server config needs fixing.

If the chain leads to a root not in Salesforce's default trust store, upload that root to Certificate and Key Management. The upload flow:

Setup → Certificate and Key Management → Import from Keystore
  Source: PEM file containing the CA's root certificate
  Label: AcmeRootCA
  Unique Name: AcmeRootCA

After upload, Salesforce trusts certificates signed by this root for outgoing callouts.

How to verify the chain in production

The Salesforce platform doesn't expose the JVM's trust store directly, but two indirect methods work:

Make a test callout from anonymous Apex:

Http http = new Http();
HttpRequest req = new HttpRequest();
req.setEndpoint('https://payment-api.example.com/v1/healthcheck');
req.setMethod('GET');
HttpResponse res = http.send(req);
System.debug(res.getStatusCode());

If the callout succeeds, the certificate chain is valid. If it throws SSLHandshakeException, the chain is broken.

For more visibility, an external tool like SSL Labs (ssllabs.com/ssltest/) inspects the target server's TLS configuration and reports chain completeness. The report names every intermediate the server sends; cross-reference against the chain the leaf certificate actually requires.

Common causes of chain breakage

A partner rotates their TLS certificate (annual renewal, typically) and the new chain is missing intermediates. Most rotation tooling handles this correctly; humans who do it manually often forget.

A CA reorganizes its hierarchy. Let's Encrypt did this in late 2021; the move from DST Root CA X3 to ISRG Root X1 broke many older clients whose trust stores hadn't been updated. Similar events happen periodically.

An intermediate certificate expires. The leaf certificate is still valid (it doesn't expire until later), but one of the chain links does. The handshake fails the next time someone connects.

A server admin disables an intermediate by accident. Sometimes during cert-rotation work, the new chain is configured but the old intermediate stays referenced. The result is a chain that points to nothing.

TLS protocol and cipher mismatches

Less commonly, the handshake fails not because of certificates but because of protocol or cipher mismatches. Salesforce deprecates old TLS versions periodically (TLS 1.0 was deprecated years ago; TLS 1.1 followed). A partner still running an old protocol can't negotiate with Salesforce.

The error message in protocol-mismatch cases is different: SSLHandshakeException: no cipher suites in common or SSLException: Connection reset. Different cause, different fix (the partner must upgrade their TLS version or cipher suites).

Edge case: self-signed certificates in sandbox

A common pattern: an internal API runs on a private VM with a self-signed certificate. Developers upload the self-signed cert to a sandbox's trust store and the integration works. The same integration in production fails because the production trust store doesn't have the cert.

The fix is to either issue the internal API a real certificate from a trusted CA (Let's Encrypt is free and trusted by default) or upload the self-signed cert to production's trust store as part of the deploy process. Whichever you choose, document it; the next person to deploy this integration into a new environment will hit the same issue.

Edge case: chain depth limits

The JVM has a maximum chain depth (default 8 levels). A certificate chain deeper than that fails validation even if every cert in the chain is valid. This is rare but happens with overly complex private-CA hierarchies.

The fix is to flatten the hierarchy or, if that's not possible, ask Salesforce Support whether the limit can be raised for your org. Most orgs never hit this limit.

Diagnosing in production

When the error fires:

  1. Capture the exact endpoint that fails. The error stack trace names the URL.
  2. Run openssl s_client -showcerts -connect <host>:<port> from a machine outside Salesforce. Confirm the chain looks complete.
  3. Compare today's chain to a known-good capture from before the incident. What changed?
  4. Check the leaf certificate's Not Before date. If it's recent, the cert was rotated. The rotation is the prime suspect.
  5. If the chain looks complete and goes to a normal CA, check Salesforce's trust store status. The Salesforce Trust site (status.salesforce.com) sometimes announces trust-store updates.
  6. If the chain goes to a private CA, verify the CA's certificate is uploaded in Certificate and Key Management.

Most incidents resolve once the chain is repaired on the server side. The remaining cases involve trust-store updates that Salesforce handles in scheduled releases.

Test patterns

A health-check test that runs daily against each external endpoint:

@isTest
private class IntegrationHealthTest {
    @isTest
    static void testPaymentAPIHandshake() {
        Test.setMock(HttpCalloutMock.class, new PaymentAPIMock());
        HttpResponse res = PaymentClient.charge(1.00, 'test_token');
        System.assertEquals(200, res.getStatusCode());
    }
}

The mock keeps the test fast and deterministic. To catch real handshake regressions, run a separate canary job that makes a live callout to each endpoint at least daily and alerts on failure.

For canary monitoring outside Salesforce, a scheduled job in a CI system runs openssl s_client against each endpoint your integrations depend on. The job alerts when chains change unexpectedly or when expiration is approaching.

Defensive habits

Subscribe to certificate expiration alerts. Many CAs send email reminders 30 and 7 days before expiration. Adding the security team and the integration owners to those lists prevents surprises.

Document every endpoint your org calls. A central inventory of (URL, owning team, certificate fingerprint, expiration date) makes incident response faster. The inventory updates whenever an integration is added or rotated.

Standardize on real CA-issued certs everywhere. Self-signed and private-CA certs are a maintenance burden disproportionate to their security benefit; Let's Encrypt and similar services issue free, trusted certs in seconds. Reserve private CAs for genuinely high-security internal use cases.

Test the integration against a fresh sandbox occasionally. Sandboxes inherit the trust store state at refresh time. An integration that secretly depends on a custom cert uploaded years ago will break the first time anyone refreshes the sandbox and forgets to re-upload.

Quick recovery checklist

When PKIX errors fire across multiple endpoints:

  1. Identify whether the failure is endpoint-specific or org-wide.
  2. For endpoint-specific failures, check the chain with openssl s_client.
  3. If the chain is incomplete, work with the partner to fix their server config.
  4. If the chain is to a non-default CA, upload the CA root to Certificate and Key Management.
  5. For org-wide failures, check Salesforce trust status and recent maintenance announcements.
  6. If the error returns intermittently, consider a TLS version or cipher mismatch.

Most incidents resolve in an hour or two once the chain shape is understood. The longer ones involve coordinating with the partner's infrastructure team to fix their TLS config.

Further reading from Salesforce

Related dictionary terms

Share this fix

Share on LinkedInShare on X

Related Integration errors