{"record":{"id":"2d2c1193ce95a6aa","repo":"AdguardTeam/AdGuardHome","slug":"parsing-certificate-at-index-d-w","errorCode":null,"errorMessage":"parsing certificate at index %d: %w","messagePattern":"parsing certificate at index (.+?): %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/aghtls/defaultmanager.go","lineNumber":761,"sourceCode":"\t\treturn nil, false, err\n\t}\n\n\tlogger.InfoContext(ctx, \"parsing multiple pem certificates\", \"num\", len(parsedCerts))\n\n\tif !CertificateHasIP(parsedCerts[0]) {\n\t\terr = errNoIPInCert\n\t}\n\n\treturn parsedCerts, true, err\n}\n\n// parsePEMCerts parses multiple PEM-encoded certificates.\nfunc parsePEMCerts(certs []*pem.Block) (parsedCerts []*x509.Certificate, err error) {\n\tfor i, cert := range certs {\n\t\tvar parsed *x509.Certificate\n\t\tparsed, err = x509.ParseCertificate(cert.Bytes)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"parsing certificate at index %d: %w\", i, err)\n\t\t}\n\n\t\tparsedCerts = append(parsedCerts, parsed)\n\t}\n\n\tif len(parsedCerts) == 0 {\n\t\treturn nil, errors.Error(\"empty certificate\")\n\t}\n\n\treturn parsedCerts, nil\n}\n\n// validatePKey validates the private key, returning its type.  It returns an\n// empty string if error occurs.\nfunc validatePKey(pkey []byte) (keyType string, err error) {\n\tvar key *pem.Block\n\n\t// Go through all pem blocks, but take first valid pem block and drop the","sourceCodeStart":743,"sourceCodeEnd":779,"githubUrl":"https://github.com/AdguardTeam/AdGuardHome/blob/b41aefbe51c8dde65e2c50f093996afa0502edf9/internal/aghtls/defaultmanager.go#L743-L779","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\n# chain.pem contains a stray PRIVATE KEY block\n// after\n# chain.pem contains only CERTIFICATE blocks, leaf first","handlingStrategy":"validation","validationCode":"rest := pemData\nfor {\n    block, rest := pem.Decode(rest)\n    if block == nil { break }\n    if block.Type != \"CERTIFICATE\" { return fmt.Errorf(\"non-certificate block: %s\", block.Type) }\n    if _, err := x509.ParseCertificate(block.Bytes); err != nil {\n        return fmt.Errorf(\"bad block: %w\", err)\n    }\n}","typeGuard":null,"tryCatchPattern":"if err := mgr.LoadTLSConfig(ctx, conf); err != nil {\n    // surface index from message; isolate and re-download the offending cert\n}","preventionTips":["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"],"tags":["tls","x509","pem","parsing","certificate"],"backgroundTag":"pem-parse-error","analyzedSha":"b41aefbe51c8dde65e2c50f093996afa0502edf9","analyzedAt":"2026-08-27T04:57:55.097Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}