caddyserver/caddy · error

acme challenge %q is not supported

Error message

acme challenge %q is not supported

What it means

Returned by ACMEChallenge.validate() when the configured challenge type is not one of the supported constants: http-01, dns-01, tls-alpn-01. Note UnmarshalJSON deliberately normalizes (trim + lowercase) but does not validate, so this error appears later, at provisioning/validate time, once the normalized string is checked. The %q formatting shows the exact (already-lowercased) value.

Source

Thrown at modules/caddypki/acmeserver/challenges.go:26

	"github.com/smallstep/certificates/authority/provisioner"
)

// ACMEChallenge is an opaque string that represents supported ACME challenges.
type ACMEChallenge string

const (
	HTTP_01     ACMEChallenge = "http-01"
	DNS_01      ACMEChallenge = "dns-01"
	TLS_ALPN_01 ACMEChallenge = "tls-alpn-01"
)

// validate checks if the given challenge is supported.
func (c ACMEChallenge) validate() error {
	switch c {
	case HTTP_01, DNS_01, TLS_ALPN_01:
		return nil
	default:
		return fmt.Errorf("acme challenge %q is not supported", c)
	}
}

// The unmarshaller first marshals the value into a string. Then it
// trims any space around it and lowercase it for normaliztion. The
// method does not and should not validate the value within accepted enums.
func (c *ACMEChallenge) UnmarshalJSON(b []byte) error {
	var s string
	if err := json.Unmarshal(b, &s); err != nil {
		return err
	}
	*c = ACMEChallenge(strings.ToLower(strings.TrimSpace(s)))
	return nil
}

// String returns a string representation of the challenge.
func (c ACMEChallenge) String() string {
	return strings.ToLower(string(c))

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Use exactly one of: http-01, dns-01, tls-alpn-01 (hyphens, lowercase; surrounding space/case are normalized away)
  2. Remove tls-sni-01 — it is not supported anywhere modern
  3. Run `caddy validate --config Caddyfile` — this error fires at validate time before serving

Example fix

# before
acme_server {
  challenges tls-sni-01
}

# after
acme_server {
  challenges http-01 dns-01
}
Defensive patterns

Strategy: validation

Validate before calling

var supportedChallenges = map[string]bool{"http-01": true, "dns-01": true, "tls-alpn-01": true}
func validChallenges(cs []string) error {
    for _, c := range cs {
        if !supportedChallenges[strings.ToLower(strings.TrimSpace(c))] {
            return fmt.Errorf("unsupported challenge %q", c)
        }
    }
    return nil
}

Type guard

func isValidChallenge(c string) bool {
    switch strings.ToLower(strings.TrimSpace(c)) {
    case "http-01", "dns-01", "tls-alpn-01":
        return true
    }
    return false
}

Prevention

When it happens

Trigger: Configuring the acme_server handler with `challenges tls-sni-01` (a removed challenge), `challenges HTTP-01` after normalization still mismatches (this one is actually fine — it lowercases to http-01), or a typo like `dns_01`, `http01`, or `tls-alpn`. Any string outside the three constants hits the default branch.

Common situations: Carrying over tls-sni-01 from very old ACME configs (it was deprecated for security reasons); underscore vs hyphen confusion (dns_01 vs dns-01); missing hyphen (http01 vs http-01); hand-written JSON with "challenges": ["HTTP_01"].

Related errors


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/a82af771848bf4b7. Report an issue: GitHub.