{"record":{"id":"d7b7ee6e76a37e2a","repo":"caddyserver/caddy","slug":"parsing-certificate-from-url-s-v","errorCode":null,"errorMessage":"parsing certificate from URL %s: %v","messagePattern":"parsing certificate from URL (.+?): (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddytls/capools.go","lineNumber":706,"sourceCode":"\t\t\treturn err\n\t\t}\n\t\tif res.StatusCode < 200 || res.StatusCode >= 300 {\n\t\t\treturn fmt.Errorf(\"HTTP %d fetching CA certificate bundle from %s\", res.StatusCode, uri)\n\t\t}\n\t\t// Parse PEM to extract certificates\n\t\tpemData := pembs\n\t\tfor len(pemData) > 0 {\n\t\t\tvar block *pem.Block\n\t\t\tblock, pemData = pem.Decode(pemData)\n\t\t\tif block == nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif block.Type != \"CERTIFICATE\" {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tcert, err := x509.ParseCertificate(block.Bytes)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"parsing certificate from URL %s: %v\", uri, err)\n\t\t\t}\n\t\t\tcaPool.AddCert(cert)\n\t\t\tcerts = append(certs, cert)\n\t\t}\n\t}\n\thcp.pool = caPool\n\thcp.certs = certs\n\treturn nil\n}\n\n// Syntax:\n//\n//\ttrust_pool http [<endpoints...>] {\n//\t\t\tendpoints \t<endpoints...>\n//\t\t\ttls \t\t<tls_config>\n//\t}\n//\n// tls_config:","sourceCodeStart":688,"sourceCodeEnd":724,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddytls/capools.go#L688-L724","documentation":"The HTTP CA pool downloaded the bundle successfully, but a PEM CERTIFICATE block inside the response body failed x509.ParseCertificate. The endpoint served PEM-framed data that is not valid DER certificate bytes.","triggerScenarios":"The URL serves an HTML error page with an embedded CERTIFICATE-looking block, a partially-written bundle, a truncated proxy response, or non-certificate DER wrapped in a CERTIFICATE PEM block.","commonSituations":"CDN/proxy serving a truncated or interpolated body; misconfigured endpoint returning docs pages; bundles regenerated mid-upload; corporate TLS-inspection proxies mangling responses.","solutions":["Download the body with curl and validate every certificate: `curl -s URL | openssl storeutl -noout -text /dev/stdin` or split blocks and run `openssl x509 -noout -text` on each.","Fix the server-side bundle generation so only complete, valid certificates are served.","If a proxy is mangling the body, bypass it or pin to a `file` trust pool updated out-of-band."],"exampleFix":"# before\ntrust_pool http https://ca.example.com/bundle   # serves HTML error page with stray PEM\n\n# after\n# host a verified bundle:\ntrust_pool http https://ca.example.com/bundle.pem","handlingStrategy":"validation","validationCode":"// verify the served body contains only parseable certificates\nfunc validateBundleBody(body []byte) error {\n\trest := body\n\tn := 0\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\tif _, err := x509.ParseCertificate(block.Bytes); err != nil {\n\t\t\treturn fmt.Errorf(\"unparseable certificate in bundle: %w\", err)\n\t\t}\n\t\tn++\n\t}\n\tif n == 0 {\n\t\treturn errors.New(\"bundle contains no certificates\")\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Generate bundles programmatically from real certificates; never hand-edit.","Serve bundles with Content-Length set and disable any HTML error-page injection on that path.","Checksum published bundles and alert on drift."],"tags":["caddy","caddytls","certificate","pem","parsing","http"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}