Fix an incomplete certificate chain (works in Chrome, fails everywhere else)

Published October 23, 2026 · about a 7-minute read

This is one of my favorite bugs to diagnose, because the symptom is so misleading. Your site loads perfectly in Chrome. Padlock's there, no warning, looks great. Then your mobile app throws an SSL error, a partner's API call fails, your payment webhook stops firing, and someone on an Android phone says the site won't open. Same certificate, wildly different results. The culprit is almost always an incomplete certificate chain — a missing intermediate. Here's what's actually going on.

What a certificate chain is

When a browser connects to your site over HTTPS, it doesn't just trust your certificate because it exists. It follows a chain of signatures up to something it already trusts:

Your certificate (leaf)
   └─ signed by → Intermediate certificate
         └─ signed by → Root certificate (in the client's trust store)

The root lives in the client's trust store — baked into the operating system or browser. You don't send it, and you can't; the client already has it. The intermediate sits in between, and this is the one that matters: your server has to hand it over during the TLS handshake, because the client almost certainly doesn't have it. Your job is to send the leaf plus every intermediate so the client can draw an unbroken line from your certificate to a root it trusts.

Miss the intermediate, and the chain has a gap. The client is holding your leaf and a root, with nothing connecting them.

Why Chrome hides the problem

Here's the maddening part — and the reason this bug ships to production. A missing intermediate doesn't fail everywhere. It fails selectively, and the one client you test in is usually the one that forgives it:

So the classic signature of this bug: it's green in your browser and red everywhere a machine talks to you. The server-to-server traffic you can't see in a browser — APIs, webhooks, mobile apps — is exactly where it bites.

The giveaway error from curl is SSL certificate problem: unable to get local issuer certificate. If you've seen that against a site that looks fine in Chrome, you've found an incomplete chain.

Confirm it in one command

Don't guess — look at what your server actually sends. From any machine with OpenSSL:

openssl s_client -connect yourdomain.com:443 -showcerts

Read the certificate list it prints back. You want to see your leaf certificate and at least one intermediate (look for the s: subject and i: issuer lines — a proper chain shows each certificate's issuer matching the next certificate's subject). If you only see one certificate, that's your problem: the server is sending the leaf alone. You can also read the Verify return code at the bottom — anything other than 0 (ok) is a chain or trust issue.

The fix (usually two minutes)

You're not reissuing anything. You just need the server to send the intermediate too.

Reload the server, run the openssl command again, and confirm the intermediate now shows up and the verify code is 0. Then test with curl from outside to be sure the machines are happy, not just the browsers.

Why this keeps happening

Certificate chains break on renewal. A cert gets reissued, a config points at the wrong file, a CA rotates its intermediate, a server migration copies over cert.pem instead of fullchain.pem — and because it still looks fine in Chrome, nobody notices until a machine complains. With certificates now renewing more often and lifespans shrinking toward 47 days, there are simply more renewal events where this can go wrong. It's the same lesson as a silently expiring certificate: the browser you happen to test in is the least reliable place to judge your TLS health.

Check from the outside, with a tool that doesn't forgive a missing intermediate, and check on a schedule — not just the day you set it up.

Catch chain problems before your APIs do

Perimeter validates your full certificate chain the strict way — the way curl, Android and payment gateways do, not the forgiving way Chrome does — alongside your headers, DNS and accessibility. And it re-checks on a schedule, so a renewal that quietly drops the intermediate gets flagged before a webhook or mobile app fails. Free, no signup.

Monitor your certificates → · Agency plan $29/mo, up to 25 domains