Certbot fullchain missing intermediates

I have the same problem on different linux distros, running acme clients such as certbot, acme.sh & simple-acme.

I am adding the missing intermediate with scripting and point applications to the adjusted fullchain.

But just to clarify, for f.x. certbot, should the fullchain.pem file contain:
leaf + YR1 +Root YR or not? As it is we get

leaf + YR1 only. Is this a acme client issue or what?

For certbot f.x.

@datao I moved your post to its own thread. We like each unique problem to have its own to better focus on your specific problem.

While your symptom was the same as the other thread it is likely caused by different things. We have seen a small number of people reporting this. So far each has turned out to be something going wrong on their local system. There have been no confirmed cases of Let's Encrypt issuing an incorrect chain.

Yes, there should be 3 certificates in fullchain for an RSA cert. The leaf, an intermediate leading to YR, and an intermediate leading to ISRG Root X1.

Let's start by gathering some further info. You would have been shown the form below had you posted in Help initially. We'll focus on Certbot even though you said you got the same problem with several ACME Clients.

=========================================

Please fill out the fields below so we can help you better. Note: you must provide your domain name to get help. Domain names for issued certificates are all made public in Certificate Transparency logs (e.g. https://crt.sh/?q=example.com), so withholding your domain name here does not increase secrecy, but only makes it harder for us to provide help.
My domain is:

I ran this command:

It produced this output:

My web server is (include version):

The operating system my web server runs on is (include version):

My hosting provider, if applicable, is:

I can login to a root shell on my machine (yes or no, or I don't know):

I'm using a control panel to manage my site (no, or provide the name and version of the control panel):

The version of my client is (e.g. output of certbot --version or certbot-auto --version if you're using Certbot):

Okay so the recent tests I ran were on:
Certbot 3.1.0
simple-acme 2.3.4.2084

I want to provide more information, but first, what about the OP of the original thread reporting that when he tries to validate the URLs of Let's Encrypt's own test URLs he gets invalid SSL?

I get the same from my linux distros, here a random Ubuntu 24.04 LTS:

curl https://valid.yr.test-certs.letsencrypt.org/
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
# openssl s_client -connect valid.yr.test-certs.letsencrypt.org:443 -showcerts </dev/null 2>/dev/null | grep -E "( s| i):" 
 0 s:
   i:C=US, O=Let's Encrypt, CN=YR1
 1 s:C=US, O=Let's Encrypt, CN=YR1
   i:C=US, O=ISRG, CN=Root YR

Shouldn't those URLs present 3 certs when the command is run against them?

Can someone just confirm that when they renew via certbot since May 28-29 their fullchain.pem files contain all 3 certs? (not 2, like mine)

I am also managing some Fortinet FortiWeb's running Let's Encrypt and they have updated some LE certs since May 28-29 and they contain all 3 certs when I run against their URLs, no problem.

They were misinterpreting what they saw. The YR and YE roots are not yet in those o/s ca root stores yet.

We have run multiple tests and the correct chain is returned by Let's Encrypt. We have used both RSA and ECDSA certs as they have different chains.

I noted we've had other reports and resolved them. Turns out those systems were "damaging" the chain locally or dropping parts of the chain as they exported them to other systems.

The default certbot configuration will result in a fullchain.pem similar https://valid.x1.test-certs.letsencrypt.org/ with three certificates, yes. leaf-signed-by-intermediate, intermediate-signed-by-root-Y, root-Y-signed-by-X1. With "E" instead of "R" if using ECDSA instead of RSA.

 0 s:
   i:C=US, O=Let's Encrypt, CN=YR2
   a:PKEY: RSA, 2048 (bit); sigalg: sha256WithRSAEncryption
   v:NotBefore: Jun  1 22:23:45 2026 GMT; NotAfter: Jun  8 14:23:44 2026 GMT
 1 s:C=US, O=Let's Encrypt, CN=YR2
   i:C=US, O=ISRG, CN=Root YR
   a:PKEY: RSA, 2048 (bit); sigalg: sha256WithRSAEncryption
   v:NotBefore: Sep  3 00:00:00 2025 GMT; NotAfter: Sep  2 23:59:59 2028 GMT
 2 s:C=US, O=ISRG, CN=Root YR
   i:C=US, O=Internet Security Research Group, CN=ISRG Root X1
   a:PKEY: RSA, 4096 (bit); sigalg: sha256WithRSAEncryption
   v:NotBefore: May 13 00:00:00 2026 GMT; NotAfter: Sep  2 23:59:59 2032 GMT

If that's not what you're seeing, then you need to give a lot more details on how your server is running and constructing the chain that you're using.

Yes, but the ECDSA fullchain also has an extra intermediate leading to ISRG Root X2 so that's another difference. Roughly like this

subject=
issuer=C=US, O=Let's Encrypt, CN=YE1

subject=C=US, O=Let's Encrypt, CN=YE1
issuer=C=US, O=ISRG, CN=Root YE

subject=C=US, O=ISRG, CN=Root YE
issuer=C=US, O=Internet Security Research Group, CN=ISRG Root X2

subject=C=US, O=Internet Security Research Group, CN=ISRG Root X2
issuer=C=US, O=Internet Security Research Group, CN=ISRG Root X1

Well then, I think you're probably right that it's the setup in our infrastructure causing this.

In my case my linux acme clients request certs from a local acme server, which itself requests from Let's Encrypt & does TXT validation & whatnot & sends the certs to the clients. It could be that the extra intermediates get "eaten" along the way before they are delivered to clients.

I will note that my Windows servers running win-acme & simple-acme seem to receive the whole chain as they should though.

If no one else has a problem with their fullchain.pem file when requesting directly from Let's Encrypt, then it's clearly the vendor of my acme server I need to talk to at this point.

Yes, that is definitely the place to start! You can refer them here for help or questions. Or you just act as go-between. We can help sort it out but that is almost certainly where the problem lies.

Which client are you using to obtain certificates?

I have done tests yesterday with certbot directly towards Let's Encrypt (which works fine) & then towards our own acme server where all but 1 intermediate clearly gets eaten, so the vendor is troubleshooting that issue and will get back to me hopefully soon.

This is off the topic, but I wanted to ask, when LE provides these tests links shouldn't they validate from f.x.

SSL Checker ?
I am maybe misunderstanding their purpose but it seems it has only leaf + 1 intermediate installed as is?

Not sure what you mean by that. But, the "valid" test link for YR is https://valid.yr.test-certs.letsencrypt.org/

That sends a leaf and the single intermediate leading to Root YR. That request will fail validation unless you have Root YR in your trusted store. Getting YR and YE into trusted stores is in process. You need to know what the test is designed to do in various circumstances.

Browsers are poor ways to check what a server sends because they work very hard to show a "clean" page to the user if they can build the needed trust chain themselves. They do this with caches and possibly preloaded intermediates. Even some cert test sites will do this.

A better way to check a chain is with openssl. Or even curl.

echo|openssl s_client -connect valid.yr.test-certs.letsencrypt.org:443

CONNECTED(00000003)
depth=1 C = US, O = Let's Encrypt, CN = YR2
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0
verify return:1
---
Certificate chain
 0 s:
   i:C = US, O = Let's Encrypt, CN = YR2
   a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
   v:NotBefore: Jun  3 10:55:00 2026 GMT; NotAfter: Jun 10 02:54:59 2026 GMT
 1 s:C = US, O = Let's Encrypt, CN = YR2
   i:C = US, O = ISRG, CN = Root YR
   a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
   v:NotBefore: Sep  3 00:00:00 2025 GMT; NotAfter: Sep  2 23:59:59 2028 GMT

And, the example "expired" test link gives this:

echo|openssl s_client expired.yr.test-certs.letsencrypt.org:443

CONNECTED(00000003)
depth=1 C = US, O = Let's Encrypt, CN = YR2
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0
verify error:num=10:certificate has expired
notAfter=May 27 22:44:36 2026 GMT
verify return:1
depth=0
notAfter=May 27 22:44:36 2026 GMT
verify return:1
---
Certificate chain
 0 s:
   i:C = US, O = Let's Encrypt, CN = YR2
   a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
   v:NotBefore: May 21 06:44:37 2026 GMT; NotAfter: May 27 22:44:36 2026 GMT
 1 s:C = US, O = Let's Encrypt, CN = YR2
   i:C = US, O = ISRG, CN = Root YR
   a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
   v:NotBefore: Sep  3 00:00:00 2025 GMT; NotAfter: Sep  2 23:59:59 2028 GMT

In this case if YR was in the trusted root store of my system the validation would still fail because of the expired cert.