puppetlabs/puppet · error · Puppet::Error
The certificate %{certname} must be cleaned from the CA firs
Error message
The certificate %{certname} must be cleaned from the CA first. To fix this,
run the following commands on the CA:
puppetserver ca clean --certname %{certname}
puppet ssl clean What it means
Raised by `Puppet::Application::SSL#clean`: before deleting local files it queries the CA with `route.get_certificate(certname)`. If the CA still returns a certificate (any response other than 404), local cleaning is aborted because the CA would keep serving the old identity and the host would immediately get its stale certificate back. Note that connect failures raise a different 'Failed to connect' error, so this error specifically means the certificate is still present on the CA.
Source
Thrown at lib/puppet/application/ssl.rb:278
def clean(certname)
# make sure cert has been removed from the CA
if certname == Puppet[:ca_server]
cert = nil
begin
ssl_context = @machine.ensure_ca_certificates
route = create_route(ssl_context)
_, cert = route.get_certificate(certname, ssl_context: ssl_context)
rescue Puppet::HTTP::ResponseError => e
if e.response.code.to_i != 404
raise Puppet::Error.new(_("Failed to connect to the CA to determine if certificate %{certname} has been cleaned") % { certname: certname }, e)
end
rescue => e
raise Puppet::Error.new(_("Failed to connect to the CA to determine if certificate %{certname} has been cleaned") % { certname: certname }, e)
end
if cert
raise Puppet::Error, _(<<~END) % { certname: certname }
The certificate %{certname} must be cleaned from the CA first. To fix this,
run the following commands on the CA:
puppetserver ca clean --certname %{certname}
puppet ssl clean
END
end
end
paths = {
'private key' => Puppet[:hostprivkey],
'public key' => Puppet[:hostpubkey],
'certificate request' => Puppet[:hostcsr],
'certificate' => Puppet[:hostcert],
'private key password file' => Puppet[:passfile]
}
if options[:localca]
paths['local CA certificate'] = Puppet[:localcacert]
paths['local CRL'] = Puppet[:hostcrl]View on GitHub (pinned to e227c27540)
Solutions
- On the CA host: `puppetserver ca clean --certname <certname>` (removes the cert, CSR, and serial)
- Then on the agent: `puppet ssl clean` — get_certificate now 404s and local files are removed
- Re-run `puppet ssl bootstrap` to request a fresh certificate
- If you cannot use the CA CLI, clean via the CA API and wait for it to take effect before retrying
Example fix
# before (agent only) puppet ssl clean # => The certificate node1 must be cleaned from the CA first... # after # (on the CA host) puppetserver ca clean --certname node1.example.com # (on the agent) puppet ssl clean && puppet ssl bootstrap
Defensive patterns
Strategy: try-catch
Validate before calling
# verify the CA no longer has the cert (404) before cleaning locally session = Puppet.lookup(:http_session) ssl_context = machine.ensure_ca_certificates route = session.route_to(:puppet) begin _ignored, cert = route.get_certificate(certname, ssl_context: ssl_context) abort 'CA still serves the certificate; run puppetserver ca clean first' if cert rescue Puppet::HTTP::ResponseError => e raise unless e.response.code.to_i == 404 # 404 = safe to clean end
Try / catch
begin
Puppet::Application[:ssl].run unless ARGV.empty?
rescue Puppet::Error => e
if e.message.include?('must be cleaned from the CA first')
# orchestrate: clean on CA, then retry the local clean once
run_on_ca('puppetserver ca clean --certname', certname)
retry
end
raise
end Prevention
- Make CA-side cleanup the first step of every certificate rotation runbook
- Script rotation as: clean on CA, then `puppet ssl clean`, then `puppet ssl bootstrap`
- Never delete only the agent's ssl directory and assume the CA forgets the host
When it happens
Trigger: Running `puppet ssl clean` while the CA still has a signed certificate for the certname; the rescue clauses let a 404 pass through (cert already cleaned) and turn non-404 HTTP errors into the connect-failure error instead.
Common situations: Rotating a compromised or mis-keyed host where the operator wiped the local ssl dir but forgot the CA; rebuilding a node with the same certname; decommission/recommission flows that skip the CA step.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Extra arguments detected: %{args} Did you mean to run: pup
- The certificate for '%{name}' has not yet been signed
- Unknown action '%{action}'
- Could not submit certificate request for '%{name}' to %{url}
- Invalid autosign value %{value}: must be 'true'/'false' or a
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/878a22a5c2e22ef3.
Report an issue: GitHub.