AdguardTeam/AdGuardHome · error
parsing certificate at index %d: %w
Error message
parsing certificate at index %d: %w
What it means
A PEM block in the certificate chain could not be parsed as an X.509 certificate. parsePEMCerts iterates all PEM blocks and x509.ParseCertificate failed on block index i — the block exists but its DER payload is corrupt or is not actually a certificate.
Source
Thrown at internal/aghtls/defaultmanager.go:761
return nil, false, err
}
logger.InfoContext(ctx, "parsing multiple pem certificates", "num", len(parsedCerts))
if !CertificateHasIP(parsedCerts[0]) {
err = errNoIPInCert
}
return parsedCerts, true, err
}
// parsePEMCerts parses multiple PEM-encoded certificates.
func parsePEMCerts(certs []*pem.Block) (parsedCerts []*x509.Certificate, err error) {
for i, cert := range certs {
var parsed *x509.Certificate
parsed, err = x509.ParseCertificate(cert.Bytes)
if err != nil {
return nil, fmt.Errorf("parsing certificate at index %d: %w", i, err)
}
parsedCerts = append(parsedCerts, parsed)
}
if len(parsedCerts) == 0 {
return nil, errors.Error("empty certificate")
}
return parsedCerts, nil
}
// validatePKey validates the private key, returning its type. It returns an
// empty string if error occurs.
func validatePKey(pkey []byte) (keyType string, err error) {
var key *pem.Block
// Go through all pem blocks, but take first valid pem block and drop theView on GitHub (pinned to b41aefbe51)
Solutions
- Regenerate or re-download the certificate chain from the issuer
- Validate offline: openssl x509 -in chain.pem -noout for each block to find the corrupt one
- If caused by partial writes, ensure the file producer writes atomically (write temp + rename)
- Remove non-certificate PEM blocks (keys, CSRs) from the chain file
Example fix
// before # chain.pem contains a stray PRIVATE KEY block // after # chain.pem contains only CERTIFICATE blocks, leaf first
Defensive patterns
Strategy: validation
Validate before calling
rest := pemData
for {
block, rest := pem.Decode(rest)
if block == nil { break }
if block.Type != "CERTIFICATE" { return fmt.Errorf("non-certificate block: %s", block.Type) }
if _, err := x509.ParseCertificate(block.Bytes); err != nil {
return fmt.Errorf("bad block: %w", err)
}
} Try / catch
if err := mgr.LoadTLSConfig(ctx, conf); err != nil {
// surface index from message; isolate and re-download the offending cert
} Prevention
- Never hand-edit PEM files; regenerate from the issuer
- Keep only CERTIFICATE blocks in chain files
- Transfer PEM files via mechanisms that preserve bytes exactly
When it happens
Trigger: A PEM block with a CERTIFICATE-type header but garbage/truncated DER content; a PEM block that is actually a key or CSR mislabeled; base64 corruption inside the PEM payload.
Common situations: Hand-edited or copy-pasted certificate files with truncated lines; concatenating files in the wrong order with stray headers; cert file partially written during atomic replacement.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- parsing tls certificate: %w
- loading tls certificate: %w
- certificate does not verify: %w
- parsing private key: %w
- certificate-key pair: %w
AI-assisted analysis of AdguardTeam/AdGuardHome@b41aefbe51 (2026-08-27).
Data as JSON: /api/errors/2d2c1193ce95a6aa.
Report an issue: GitHub.