caddyserver/caddy · error
could not convert automation policy subject '%s' to punycode
Error message
could not convert automation policy subject '%s' to punycode: %v
What it means
During AutomationPolicy.Provision, each subject (domain name) is passed through the placeholder replacer and then idna.ToASCII to convert it to punycode/ASCII form. If the conversion fails, the subject is not a valid IDNA name. The wrapped error from the idna library explains the exact problem (empty label, disallowed rune, label too long, etc.).
Source
Thrown at modules/caddytls/automation.go:190
subjects []string
magic *certmagic.Config
storage certmagic.Storage
// Whether this policy had explicit managers configured directly on it.
hadExplicitManagers bool
}
// Provision sets up ap and builds its underlying CertMagic config.
func (ap *AutomationPolicy) Provision(tlsApp *TLS) error {
// replace placeholders in subjects to allow environment variables
repl := caddy.NewReplacer()
subjects := make([]string, len(ap.SubjectsRaw))
for i, sub := range ap.SubjectsRaw {
sub = repl.ReplaceAll(sub, "")
subASCII, err := idna.ToASCII(sub)
if err != nil {
return fmt.Errorf("could not convert automation policy subject '%s' to punycode: %v", sub, err)
}
subjects[i] = subASCII
}
ap.subjects = subjects
// policy-specific storage implementation
if ap.StorageRaw != nil {
val, err := tlsApp.ctx.LoadModule(ap, "StorageRaw")
if err != nil {
return fmt.Errorf("loading TLS storage module: %v", err)
}
cmStorage, err := val.(caddy.StorageConverter).CertMagicStorage()
if err != nil {
return fmt.Errorf("creating TLS storage configuration: %v", err)
}
ap.storage = cmStorage
}
View on GitHub (pinned to 50e54ee279)
Solutions
- Inspect the subject named in the message and fix or remove the invalid character(s) — the wrapped idna error states the precise cause.
- If the subject uses {$ENV_PLACEHOLDER} syntax, confirm the environment variable is set to a valid hostname on the machine running Caddy.
- Validate names with a punycode converter (e.g. idn command or an online IDNA tool) before putting them in config.
- Remember underscores are not permitted in hostnames per IDNA; remove them or move such names out of the TLS subjects.
Example fix
# before (placeholder unset -> empty/invalid subject)
{$SITE_DOMAIN}:443 {
respond "hi"
}
# after (valid literal or verified env var)
example.com:443 {
respond "hi"
} Defensive patterns
Strategy: validation
Validate before calling
// Validate subjects before provisioning.
for _, s := range policy.SubjectsRaw {
s = repl.ReplaceAll(s, "")
if _, err := idna.ToASCII(s); err != nil {
return fmt.Errorf("subject %q fails IDNA: %v", s, err)
}
} Type guard
func isValidSubjectName(s string) bool {
_, err := idna.ToASCII(s)
return err == nil
} Prevention
- Lint hostnames in generated configs with idna.ToASCII before deploying.
- Fail builds when {$...} site-address placeholders are unset in the target environment.
- Avoid underscores and stray dots in site addresses.
When it happens
Trigger: A subject in the automation policy containing characters that cannot be IDNA-encoded: strings longer than 253 bytes, labels over 63 chars, empty labels (double dots), stray underscores placed where IDNA forbids them, or a placeholder that expanded to an empty/invalid name.
Common situations: Typos in Caddyfile site addresses (double dots, trailing garbage); environment placeholders like {$DOMAIN} unset so the subject collapses to an empty string; pasting Unicode hostnames with zero-width characters; copy/paste of wildcard names with incorrect syntax.
Related errors
- unrecognized key type: %s
- invalid TLS renegotiation level: %v
- unsupported cipher suite: %s
- protocol min (%x) cannot be greater than protocol max (%x)
- public name length (%d) must be in the range 1-255
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/3e9aaa99a54474b9.
Report an issue: GitHub.