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
- Use exactly one of: http-01, dns-01, tls-alpn-01 (hyphens, lowercase; surrounding space/case are normalized away)
- Remove tls-sni-01 — it is not supported anywhere modern
- 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
- Restrict challenge lists to the three canonical lowercase-hyphenated names
- Remove tls-sni-01 from any legacy config during upgrades
- Validate config in CI before rollout
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
- certificate lifetime (%s) should be less than intermediate c
- resolver address must have exactly one address; cannot call
- CA ID is required (use 'local' for the default CA)
- intermediate certificate lifetime must be less than actual r
- parsing listener address: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/a82af771848bf4b7.
Report an issue: GitHub.