From f0d43fd8e525a2234b30ac46f9f336b234b1608a Mon Sep 17 00:00:00 2001 From: Bryan Frimin Date: Wed, 25 Mar 2026 09:30:14 +0100 Subject: [PATCH] Fix ACME challenge retry to create fresh orders When CompleteHTTPChallenge fails, the challenge is already marked invalid by Let's Encrypt. Retrying Accept on the same challenge always fails with "authorization must be pending". Reset the domain to pending with cleared challenge data so each retry creates a new ACME order. Signed-off-by: Bryan Frimin --- pkg/certmanager/provisioner.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/pkg/certmanager/provisioner.go b/pkg/certmanager/provisioner.go index d9184db71..e1d784636 100644 --- a/pkg/certmanager/provisioner.go +++ b/pkg/certmanager/provisioner.go @@ -347,6 +347,15 @@ func (p *Provisioner) provisionDomainCertificate( domain.SSLRetryCount = domain.SSLRetryCount + 1 domain.SSLLastAttemptAt = new(time.Now()) + // Clear challenge data and reset to pending so the next attempt + // creates a fresh ACME order. Once a challenge fails validation, + // Let's Encrypt marks it as invalid and retrying the same + // challenge always fails with "authorization must be pending". + domain.HTTPChallengeToken = nil + domain.HTTPChallengeKeyAuth = nil + domain.HTTPChallengeURL = nil + domain.HTTPOrderURL = nil + if domain.SSLRetryCount >= maxRetries { p.logger.ErrorCtx( ctx, @@ -356,10 +365,8 @@ func (p *Provisioner) provisionDomainCertificate( ) domain.SSLStatus = coredata.CustomDomainSSLStatusFailed - domain.HTTPChallengeToken = nil - domain.HTTPChallengeKeyAuth = nil - domain.HTTPChallengeURL = nil - domain.HTTPOrderURL = nil + } else { + domain.SSLStatus = coredata.CustomDomainSSLStatusPending } if err := domain.Update(ctx, tx, coredata.NewNoScope()); err != nil {