{"record":{"id":"3b9743effbb4b539","repo":"JuliusBrussee/caveman","slug":"s-trailing-pem-block-is-truncated-after-d-certificate-s-so","errorCode":null,"errorMessage":"%s: trailing PEM block is truncated after %d certificate(s), so the bundle is incomplete and must not be half-trusted","messagePattern":"(.+?): trailing PEM block is truncated after (.+?) certificate\\(s\\), so the bundle is incomplete and must not be half-trusted","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shared/platform/cabundle/cabundle.go","lineNumber":74,"sourceCode":"\tvar certs []*x509.Certificate\n\trest := bundle\n\tfor {\n\t\tvar block *pem.Block\n\t\tblock, rest = pem.Decode(rest)\n\t\tif block == nil {\n\t\t\tbreak\n\t\t}\n\t\tif block.Type != \"CERTIFICATE\" {\n\t\t\tcontinue\n\t\t}\n\t\tcert, err := x509.ParseCertificate(block.Bytes)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%s: certificate %d is unparseable, so the bundle is incomplete and must not be half-trusted: %w\", path, len(certs)+1, err)\n\t\t}\n\t\tcerts = append(certs, cert)\n\t}\n\tif bytes.Contains(rest, []byte(\"-----BEGIN\")) {\n\t\treturn nil, fmt.Errorf(\"%s: trailing PEM block is truncated after %d certificate(s), so the bundle is incomplete and must not be half-trusted\", path, len(certs))\n\t}\n\tif len(certs) == 0 {\n\t\treturn nil, fmt.Errorf(\"%s contains no valid PEM certificate\", path)\n\t}\n\treturn certs, nil\n}\n","sourceCodeStart":56,"sourceCodeEnd":81,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/shared/platform/cabundle/cabundle.go#L56-L81","documentation":"After decoding all complete PEM blocks, Certificates checks whether the remaining bytes still contain '-----BEGIN'. If so, the file ends with a truncated PEM block, and the library refuses to return the certificates parsed so far — a half-trusted bundle is treated as a security risk. The error reports the file path and how many complete certificates were parsed.","triggerScenarios":"Calling Certificates (or Pool/loadRootCAs) on a PEM file whose final certificate block was cut off mid-base64 or lacks its END line — typically from a partial file write, a truncated mount/copy, or a copy-paste that dropped the tail.","commonSituations":"Kubernetes secret truncated by a size/formatting mistake; an incomplete docker build COPY of a partially downloaded bundle; editors or tools that clipped a long pasted chain; interrupted file download of a CA bundle.","solutions":["Compare the file against the source bundle: check `openssl crl2pkcs7 -nocrl -certfile bundle.pem | openssl pkcs7 -print_certs` lists every expected certificate, and re-copy/re-download the full file.","Look at the end of the file (`tail -5 bundle.pem`); ensure it ends with '-----END CERTIFICATE-----' and complete base64.","If copying certificates manually, paste each block fully including BEGIN/END lines, one certificate at a time.","Fix the pipeline producing the file (download, secret manifest, build step) so writes complete atomically (write to temp then rename)."],"exampleFix":"// before (truncated bundle)\ncat root.pem partial-intermediate.pem > bundle.pem // last block cut off\n// after\ncat root.pem full-intermediate.pem > bundle.pem\ntail -1 bundle.pem # => -----END CERTIFICATE-----","handlingStrategy":"validation","validationCode":"func bundleComplete(path string) error {\n    data, err := os.ReadFile(path)\n    if err != nil { return err }\n    if bytes.Contains(data, []byte(\"-----BEGIN\")) && !bytes.Contains(data, []byte(\"-----END CERTIFICATE-----\")) {\n        return fmt.Errorf(\"%s ends with a truncated PEM block\", path)\n    }\n    return nil\n}\n// call before cabundle.Certificates","typeGuard":null,"tryCatchPattern":"certs, err := cabundle.Certificates(path)\nif err != nil && strings.Contains(err.Error(), \"truncated\") {\n    return fmt.Errorf(\"TLS bundle %s is incomplete; re-copy the full chain: %w\", path, err)\n}","preventionTips":["Check files end with '-----END CERTIFICATE-----' after every copy/download.","Compare the certificate count (`grep -c 'BEGIN CERTIFICATE'`) against the CA-provided chain.","Write bundles atomically (temp file + rename) so partial writes are never observed.","Verify mounted secrets/ConfigMaps fully round-trip after deployment."],"tags":["tls","certificates","pem","fail-closed"],"backgroundTag":"invalid-argument-format","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}