puppetlabs/puppet · error · Puppet::Error

The private key is missing from '%{path}'

Error message

The private key is missing from '%{path}'

What it means

CertProvider#load_private_key raises Puppet::Error when required is true and load_pem finds nothing at @hostprivkey, or at privatekeydir/<name>.pem when hostprivkey is unset. The node expects a client identity but the private half is gone, and the signed certificate cannot be used without its key.

Source

Thrown at lib/puppet/x509/cert_provider.rb:216

  # Load a private key from the configured `privatekeydir`. For
  # historical reasons, names are case-insensitive.
  #
  # @param name [String] The private key identity
  # @param required [Boolean] If true, raise if it is missing
  # @param password [String, nil] If the private key is encrypted, decrypt
  #   it using the password. If the key is encrypted, but a password is
  #   not specified, then the key cannot be loaded.
  # @return (see #load_private_key_from_pem)
  # @raise (see #load_private_key_from_pem)
  # @raise [Puppet::Error] if the private key cannot be loaded
  #
  # @api private
  def load_private_key(name, required: false, password: nil)
    path = @hostprivkey || to_path(@privatekeydir, name)
    pem = load_pem(path)
    if !pem && required
      raise Puppet::Error, _("The private key is missing from '%{path}'") % { path: path }
    end

    pem ? load_private_key_from_pem(pem, password: password) : nil
  rescue SystemCallError => e
    raise Puppet::Error.new(_("Failed to load private key for '%{name}'") % { name: name }, e)
  end

  # Load a PEM encoded private key.
  #
  # @param pem [String] PEM encoded private key
  # @param password [String, nil] If the private key is encrypted, decrypt
  #   it using the password. If the key is encrypted, but a password is
  #   not specified, then the key cannot be loaded.
  # @return [OpenSSL::PKey::RSA, OpenSSL::PKey::EC] The private key
  # @raise [OpenSSL::PKey::PKeyError] The `pem` text does not contain a valid key
  #
  # @api private
  def load_private_key_from_pem(pem, password: nil)

View on GitHub (pinned to e227c27540)

Solutions

  1. Check `puppet config print certname hostprivkey privatekeydir` and look for <certname>.pem under privatekeydir
  2. If certname drifted, set certname back to the enrolled name or move/rename the key file to match
  3. Restore the key from backup with 0600 permissions and correct ownership
  4. If the key is lost, re-enroll: remove cert, key, and CSR files, run `puppet agent -t`, sign the new request on the CA

Example fix

# before: cert exists, key lost
$ ls ssl/certs/agent.example.com.pem ssl/private_keys/
ssl/certs/agent.example.com.pem

# after: re-enroll
$ rm ssl/certs/agent.example.com.pem
$ puppet agent -t    # new key + CSR; sign on CA; cert is fetched
Defensive patterns

Strategy: validation

Validate before calling

key = Puppet[:hostprivkey] || File.join(Puppet[:privatekeydir], "#{Puppet[:certname]}.pem")
raise "private key missing at #{key}" unless File.size?(key)

Try / catch

begin
  key = provider.load_private_key(name, required: true, password: pw)
rescue Puppet::Error => e
  reenroll!(name) if e.message.include?('private key is missing')
  raise
end

Prevention

When it happens

Trigger: SSLProvider#load_context finds a client certificate but the key file is missing; certname changed (fqdn/certname setting drift) so the key lives under a different filename in privatekeydir; key removed by rotation or cleanup scripts; file unreadable to the running user.

Common situations: Certificate restored from backup but the key was not (or vice versa); host renamed causing certname mismatch; ssldir mounted differently between root and the puppet user; backups that skip private_keys.

Related errors


AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21). Data as JSON: /api/errors/355f176255b5db4a. Report an issue: GitHub.