Billionmail/BillionMail · error

Failed to set Cloudflare DNS verification: {}

Error message

Failed to set Cloudflare DNS verification: {}

What it means

For vtype == "dns" with dnsProvider == "cloudflare", SetDnsCloudflare constructs a lego Cloudflare provider using dnsProviderToken and registers it for the dns-01 challenge. The error means Cloudflare provider setup failed — usually an invalid or wrongly scoped API token/key, or using the legacy Global API Key format where an API Token is expected.

Source

Thrown at core/internal/service/acme/acme.go:429

		case "alidns":
			err = SetDnsAliyun(ctx, client, dnsProviderToken)
			if err != nil {
				return "", "", errors.New(public.LangCtx(ctx, "Failed to set Alibaba Cloud DNS verification: {}", err.Error()))
			}
		case "cloudxns":
			err = SetDnsCloudxns(ctx, client, dnsProviderToken)
			if err != nil {
				return "", "", errors.New(public.LangCtx(ctx, "Failed to set CloudXNS DNS verification: {}", err.Error()))
			}
		case "azuredns":
			err = SetDnsAzuredns(ctx, client, dnsProviderToken)
			if err != nil {
				return "", "", errors.New(public.LangCtx(ctx, "Failed to set AzureDNS verification: {}", err.Error()))
			}
		case "cloudflare":
			err = SetDnsCloudflare(ctx, client, dnsProviderToken)
			if err != nil {
				return "", "", errors.New(public.LangCtx(ctx, "Failed to set Cloudflare DNS verification: {}", err.Error()))
			}
		case "godaddy":
			err = SetDnsGodaddy(ctx, client, dnsProviderToken)
			if err != nil {
				return "", "", errors.New(public.LangCtx(ctx, "Failed to set Godaddy DNS verification: {}", err.Error()))
			}
		default:
			return "", "", errors.New(public.LangCtx(ctx, "Unsupported DNS provider: {}", dnsProvider))
		}
	}

	// Register or query existing user on ACME server
	var reg *registration.Resource
	// Try to query existing registration first (same key = same account)
	reg, err = client.Registration.QueryRegistration()
	if err != nil || reg == nil {
		// No existing registration, register new account
		reg, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Create a fresh Cloudflare API Token scoped to the zone with Zone:DNS:Edit and set it as dnsProviderToken
  2. If using the Global API Key, supply it in the combined form the lego provider expects (email + key) per the app's token format
  3. Verify the token with the Cloudflare API (list zones) before retrying the certificate application

Example fix

// before
dnsProviderToken = "legacyGlobalKey" // without account email
// after
dnsProviderToken = "cf_api_token_with_dns_edit"
Defensive patterns

Strategy: validation

Validate before calling

if dnsProvider == "cloudflare" && len(strings.TrimSpace(dnsProviderToken)) < 20 {
    return errors.New("cloudflare API token looks invalid")
}
// optional live check:
// GET https://api.cloudflare.com/client/v4/zones with Bearer token must return success

Type guard

func isCloudflareConfigured(vtype, provider, token string) bool {
    return vtype == "dns" && provider == "cloudflare" && strings.TrimSpace(token) != ""
}

Try / catch

cert, _, err := ApplySSLWithExistingServer(ctx, ...)
if err != nil && strings.Contains(err.Error(), "Cloudflare") {
    return fmt.Errorf("check Cloudflare API token scope (Zone:DNS:Edit): %w", err)
}

Prevention

When it happens

Trigger: ApplySSLWithExistingServer (via Apply, StartRenew, ApplyLetsEncryptCertWithHttp, ApplyConsoleCert) with vtype="dns", dnsProvider="cloudflare", and a dnsProviderToken that is an expired/revoked API token, a Global API Key supplied without the account email, or a token lacking Zone:DNS:Edit permission for the domain.

Common situations: Rotated Cloudflare token not updated in the app; token created for the wrong zone; pasting the Global API Key where the app expects a Bearer API token (or vice versa).

Related errors


AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05). Data as JSON: /api/errors/61ca7309c4bd1ae6. Report an issue: GitHub.