{"record":{"id":"324ed2e01eeffed5","repo":"puppetlabs/puppet","slug":"failed-to-parse-ca-certificates-as-pem","errorCode":null,"errorMessage":"Failed to parse CA certificates as PEM","messagePattern":"Failed to parse CA certificates as PEM","errorType":"exception","errorClass":"OpenSSL::X509::CertificateError","httpStatus":null,"severity":"error","filePath":"lib/puppet/x509/cert_provider.rb","lineNumber":77,"sourceCode":"    if !pem && required\n      raise Puppet::Error, _(\"The CA certificates are missing from '%{path}'\") % { path: @capath }\n    end\n\n    pem ? load_cacerts_from_pem(pem) : nil\n  rescue SystemCallError => e\n    raise Puppet::Error.new(_(\"Failed to load CA certificates from '%{capath}'\") % { capath: @capath }, e)\n  end\n\n  # Load PEM encoded CA certificates.\n  #\n  # @param pem [String] PEM encoded certificate(s)\n  # @return [Array<OpenSSL::X509::Certificate>] Array of CA certs\n  # @raise [OpenSSL::X509::CertificateError] The `pem` text does not contain a valid cert\n  #\n  # @api private\n  def load_cacerts_from_pem(pem)\n    # TRANSLATORS 'PEM' is an acronym and shouldn't be translated\n    raise OpenSSL::X509::CertificateError, _(\"Failed to parse CA certificates as PEM\") if pem !~ CERT_DELIMITERS\n\n    pem.scan(CERT_DELIMITERS).map do |text|\n      OpenSSL::X509::Certificate.new(text)\n    end\n  end\n\n  # Save `crls` to the configured `crlpath`.\n  #\n  # @param crls [Array<OpenSSL::X509::CRL>] Array of CRLs to save\n  # @raise [Puppet::Error] if the CRLs cannot be saved\n  #\n  # @api private\n  def save_crls(crls)\n    save_pem(crls.map(&:to_pem).join, @crlpath, **permissions_for_setting(:hostcrl))\n  rescue SystemCallError => e\n    raise Puppet::Error.new(_(\"Failed to save CRLs to '%{crlpath}'\") % { crlpath: @crlpath }, e)\n  end\n","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/x509/cert_provider.rb#L59-L95","documentation":"Raised by CertProvider#load_cacerts_from_pem as OpenSSL::X509::CertificateError when the CA file exists but its text does not match CERT_DELIMITERS, i.e. it contains no '-----BEGIN CERTIFICATE-----' block. The same error class also surfaces from OpenSSL::X509::Certificate.new inside the scan block when an individual block is corrupt or truncated. Either way the trust store cannot be built and TLS setup aborts.","triggerScenarios":"load_cacerts(required: true) reads a localcacert whose PEM has no certificate delimiters, or a block OpenSSL cannot parse: binary DER data saved with a .pem name, an HTML/proxy error page captured instead of the cert, a truncated download, or cert and key files swapped.","commonSituations":"curl/wget fetch of the CA that hit a proxy login page; DER-formatted certs from a vendor; files mangled by Windows copies or templating that strips newlines; hand-editing ca.pem and losing the END line.","solutions":["Inspect the file: `head ca.pem` must show BEGIN/END CERTIFICATE lines and `openssl x509 -in ca.pem -noout` must parse","If it is DER, convert: `openssl x509 -inform der -in ca.der -outform pem -out ca.pem`","Re-download the CA cert from the Puppet server CA and atomically overwrite the file","Verify every BEGIN/END pair when multiple CAs are concatenated, then rerun `puppet agent -t`"],"exampleFix":"# before: file holds DER bytes\n$ openssl x509 -in ca.pem -noout\nunable to load certificate\n\n# after\n$ openssl x509 -inform der -in ca.der -outform pem -out ca.pem\n$ openssl x509 -in ca.pem -noout\nsubject=CN=Puppet CA: puppet.example.com","handlingStrategy":"validation","validationCode":"def pem_cert?(path)\n  File.read(path).match?(/-----BEGIN CERTIFICATE-----/)\nend\n\nraise \"#{Puppet[:localcacert]} is not PEM\" unless pem_cert?(Puppet[:localcacert])","typeGuard":null,"tryCatchPattern":"begin\n  certs = Puppet::X509::CertProvider.new.load_cacerts(required: true)\nrescue OpenSSL::X509::CertificateError => e\n  abort \"CA bundle at #{Puppet[:localcacert]} is not valid PEM: #{e.message}\"\nend","preventionTips":["Verify fetched certs with `openssl x509 -noout` before atomically moving them into ssldir","Never hand-edit ca.pem; replace it wholesale from the CA","CI-check ssl artifacts in images for well-formed PEM blocks"],"tags":["ruby","puppet","ssl","openssl","pem","x509"],"backgroundTag":"malformed-pem-certificate","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}