caddyserver/caddy · error

could not convert automation policy subject

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.).

Solutions

  1. Inspect the subject named in the message and fix or remove the invalid character(s) — the wrapped idna error states the precise cause.
  2. If the subject uses {$ENV_PLACEHOLDER} syntax, confirm the environment variable is set to a valid hostname on the machine running Caddy.
  3. Validate names with a punycode converter (e.g. idn command or an online IDNA tool) before putting them in config.
  4. 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

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


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

Appendix: 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)