{"record":{"id":"c72dd30c46f2ca20","repo":"aaif-goose/goose","slug":"failed-to-parse-ca-certificate-bundle","errorCode":null,"errorMessage":"Failed to parse CA certificate bundle: {}","messagePattern":"Failed to parse CA certificate bundle: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/goose-providers/src/api_client.rs","lineNumber":126,"sourceCode":"                    |e| anyhow::anyhow!(\"Failed to create identity from cert and key: {}\", e),\n                )?\n            };\n\n            Ok(Some(identity))\n        } else {\n            Ok(None)\n        }\n    }\n\n    #[cfg(any(feature = \"rustls-tls\", feature = \"native-tls\"))]\n    fn load_ca_certificates(&self) -> Result<Vec<Certificate>> {\n        match &self.ca_cert_path {\n            Some(ca_path) => {\n                let ca_pem = read_to_string(ca_path)\n                    .map_err(|e| anyhow::anyhow!(\"Failed to read CA certificate: {}\", e))?;\n\n                let certs = Certificate::from_pem_bundle(ca_pem.as_bytes())\n                    .map_err(|e| anyhow::anyhow!(\"Failed to parse CA certificate bundle: {}\", e))?;\n\n                Ok(certs)\n            }\n            None => Ok(Vec::new()),\n        }\n    }\n}\n\nimpl Default for TlsConfig {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\n/// Convert a PEM private key from any format (PKCS#1, SEC1, PKCS#8) to PKCS#8 PEM.\n///\n/// `reqwest::Identity::from_pkcs8_pem` (native-tls) only accepts PKCS#8\n/// (`-----BEGIN PRIVATE KEY-----`), but private keys in the wild come in three formats:","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose-providers/src/api_client.rs#L108-L144","documentation":"After reading the CA bundle, load_ca_certificates calls Certificate::from_pem_bundle on its bytes. If the file is valid text but not a PEM bundle (no BEGIN/END CERTIFICATE blocks, Base64 corrupted, or a lone private key), parsing fails with 'Failed to parse CA certificate bundle: {err}'. The read succeeded; the content is not a certificate bundle.","triggerScenarios":"ca_cert_path points at a file that is not PEM: a DER binary renamed .pem, a concatenated chain with a broken Base64 body, a chain with Windows line endings or stray headers that break armor detection, or a JSON/HTML error page saved by mistake (e.g. a failed download).","commonSituations":"Downloading a CA via curl without following redirects and saving an error page; cert managers writing DER despite the extension; hand-concatenated bundles with missing newlines between blocks; expired tooling emitting malformed armor.","solutions":["Inspect the file: it must contain one or more -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE----- blocks","Re-download the CA properly: curl -fsSL -o ca.pem https://proxy.example/ca.pem","Convert DER to PEM: openssl x509 -inform der -in ca.crt -out ca.pem","Ensure exactly one newline between concatenated PEM blocks"],"exampleFix":"# before\nca_cert_path: /etc/goose/tls/ca.pem   # actually DER bytes or an HTML error page\n\n# after (shell)\n$ file /etc/goose/tls/ca.pem                     # expect: PEM certificate\n$ openssl x509 -inform der -in ca.der -out /etc/goose/tls/ca.pem\n$ openssl verify -CAfile /etc/goose/tls/ca.pem server-cert.pem","handlingStrategy":"validation","validationCode":"let pem = std::fs::read_to_string(&ca_cert_path)?;\nlet blocks = pem.matches(\"-----BEGIN CERTIFICATE-----\").count();\nanyhow::ensure!(blocks > 0, \"file contains no PEM certificate blocks\");","typeGuard":"fn is_pem_certificate_bundle(path: &std::path::Path) -> bool {\n    std::fs::read_to_string(path)\n        .map(|s| s.contains(\"-----BEGIN CERTIFICATE-----\"))\n        .unwrap_or(false)\n}","tryCatchPattern":null,"preventionTips":["Sanity-check downloads: curl -fsSL and file ca.pem before trusting it","Separate newlines between concatenated PEM blocks","Validate the bundle against a known server: openssl verify -CAfile ca.pem server.pem","Prefer PEM from the CA owner over re-encoding DER yourself when possible"],"tags":["rust","tls","ca-certificate","pem","parsing"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}