cilium/cilium · error
failed to parse certificate: %w
Error message
failed to parse certificate: %w
What it means
During the TLS handshake the peer presented certificates in raw (DER) form which the handler parses with x509.ParseCertificate; one of the peer's certificates is malformed and cannot be parsed into an x509.Certificate. This happens inside the handshake verification callback, so the handshake is aborted.
Source
Thrown at pkg/auth/mutual_authhandler.go:133
// set up TLS socket
//nolint:gosec // InsecureSkipVerify is not insecure as we do the verification in VerifyPeerCertificate
tlsConn := tls.Client(conn, &tls.Config{
ServerName: m.cert.NumericIdentityToSNI(ar.remoteIdentity),
GetClientCertificate: func(info *tls.CertificateRequestInfo) (*tls.Certificate, error) {
return clientCert, nil
},
MinVersion: tls.VersionTLS13,
InsecureSkipVerify: true, // not insecure as we do the verification in VerifyPeerCertificate
VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
// verifiedChains will be nil as we set InsecureSkipVerify to true
chain := make([]*x509.Certificate, len(rawCerts))
for i, rawCert := range rawCerts {
cert, err := x509.ParseCertificate(rawCert)
if err != nil {
return fmt.Errorf("failed to parse certificate: %w", err)
}
chain[i] = cert
}
peerExpirationTime, err := m.verifyPeerCertificate(&ar.remoteIdentity, caBundle, [][]*x509.Certificate{chain})
if peerExpirationTime != nil && peerExpirationTime.Before(*expirationTime) {
expirationTime = peerExpirationTime // send down the lowest expiration time of the two certificates
}
return err
},
ClientCAs: caBundle,
RootCAs: caBundle,
})
defer tlsConn.Close()
if err := tlsConn.Handshake(); err != nil {
return nil, fmt.Errorf("failed to perform TLS handshake: %w", err)
}View on GitHub (pinned to ac7b90affa)
Solutions
- Restart the remote node's Cilium agent so it re-issues/re-loads its certificate
- Force certificate re-issuance via the certificate provider (SPIRE re-attestation) on the peer
- Verify no proxy/TLS-terminating middlebox sits between the nodes on the auth port
- Capture the peer's certificate bytes (tls debug) and confirm they are valid DER; upgrade Cilium if a known parsing bug matches
Defensive patterns
Strategy: try-catch
Try / catch
if err := authManager.Authenticate(ctx, key); err != nil {
if strings.Contains(err.Error(), "failed to parse certificate") {
// peer certificate corrupt: trigger remote agent cert re-issuance, then retry
}
} Prevention
- Avoid TLS-intercepting middleboxes on the auth port
- Monitor certificate rotation success on all nodes
- Keep agent versions consistent across the mesh
When it happens
Trigger: the VerifyPeerCertificate callback receives rawCerts from the TLS stack and x509.ParseCertificate(rawCert) errors — truncated or corrupted certificate bytes, or a peer sending a non-X.509/unexpected certificate format.
Common situations: remote agent serving a corrupt or truncated certificate after a failed rotation; a middlebox/proxy interfering with TLS; version mismatch where peers negotiate unexpected cert formats; memory corruption during cert storage.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- remote cluster configuration retrieval status unknown
- cannot process cert '%s': must be a PEM encoded certificate
- failed to get expiration time of peer certificate
- no certificate chains found
- leaf certificate cannot be a CA
AI-assisted analysis of cilium/cilium@ac7b90affa (2026-08-31).
Data as JSON: /api/errors/e2ad5915988a78da.
Report an issue: GitHub.