cloudflare/pingora · error
Failed to parse PEM
Error message
Failed to parse PEM
What it means
X509Pem::new() in the s2n backend iterates every PEM section in the buffer and expects each to parse (pem::Pem). The expect fires on the first section whose base64 body or -----BEGIN/END----- framing is malformed — stray characters, broken base64, CRLF issues, or a truncated final block. It usually runs while loading certificate chains, so one bad block aborts TLS setup/startup.
Source
Thrown at pingora-core/src/utils/tls/s2n.rs:152
get_serial(self.leaf()).unwrap()
}
pub fn raw_pem(&self) -> &[u8] {
&self.pem.raw_pem
}
}
#[derive(Debug)]
pub struct X509Pem {
pub raw_pem: Vec<u8>,
pub certs: Vec<WrappedX509>,
}
impl X509Pem {
pub fn new(raw_pem: Vec<u8>) -> Self {
let certs = Pem::iter_from_buffer(&raw_pem)
.map(|part| {
let raw_cert = part.expect("Failed to parse PEM").contents;
WrappedX509::new(raw_cert, parse_x509)
})
.collect();
X509Pem { raw_pem, certs }
}
pub fn iter(&self) -> std::slice::Iter<'_, WrappedX509> {
self.certs.iter()
}
}
fn parse_x509<C>(raw_cert: &C) -> X509Certificate<'_>
where
C: AsRef<[u8]>,
{
X509Certificate::from_der(raw_cert.as_ref())
.expect("Failed to parse certificate from DER format.")
.1View on GitHub (pinned to 0046038bd4)
Solutions
- Re-emit each certificate canonically: `openssl x509 -in broken.pem -out fixed.pem`, then concatenate the fixed blocks
- Bisect the file: run `openssl x509 -in <section> -noout` per block to find the one that fails to decode
- Remove non-CERTIFICATE blocks (keys, CSRs, commentary text) from cert chain files
- Ensure LF line endings and a trailing newline; re-transfer in binary mode
Example fix
# before: chain.pem contains a corrupt/truncated block -----BEGIN CERTIFICATE----- MIIB... (truncated mid-base64) # after: rebuild the chain from canonically re-exported certs openssl x509 -in leaf.pem -out chain.pem openssl x509 -in intermediate.pem >> chain.pem
Defensive patterns
Strategy: validation
Validate before calling
fn pem_fully_parses(buf: &[u8]) -> bool {
x509_parser::pem::Pem::iter_from_buffer(buf).all(|part| part.is_ok())
}
// before X509Pem::new(raw_pem)
anyhow::ensure!(pem_fully_parses(&raw_pem), "PEM contains a malformed section"); Prevention
- Validate PEM files in CI with openssl (each block must load) before deploy
- Generate/normalize PEMs with openssl rather than manual concatenation
- Transfer cert files in binary-safe mode; avoid CRLF translation and missing trailing newlines
- Keep only CERTIFICATE blocks in chain files
When it happens
Trigger: Loading a PEM buffer through X509Pem::new (s2n cert chain load path) where any section fails pem parsing: corrupt base64, missing END line, garbage lines, or non-PEM content mixed into the buffer.
Common situations: Hand-edited or copy-pasted PEMs with dropped characters; concatenating cert and key into one file; files without a trailing newline; CRLF line endings from Windows; secrets-injection systems mangling base64 padding.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Failed to parse certificate from DER format.
- invalid ca pem
- Failed to parse certificate from DER format.
- Failed to build listeners
- No tls feature was specified
AI-assisted analysis of cloudflare/pingora@0046038bd4 (2026-08-16).
Data as JSON: /api/errors/8315de6cc6494431.
Report an issue: GitHub.