caddyserver/caddy · error

provisioning automation policy %d: %v

Error message

provisioning automation policy %d: %v

What it means

Each user-defined policy in tls.automation.policies is provisioned in order; this error wraps the failure of policy at index %d. The wrapped message comes from AutomationPolicy.Provision (automation.go:182) and can be: subject punycode/IDNA conversion failure, storage module load failure, external certificate manager (ManagersRaw) load failure, issuer module load failure, or default issuer provisioning failure.

Source

Thrown at modules/caddytls/tls.go:317

		// if any names specified by the "automate" loader do not qualify for a public
		// certificate, we should initialize a default internal automation policy
		// (but we don't want to do this unnecessarily, since it may prompt for password!)
		if certmagic.SubjectQualifiesForPublicCert(n) {
			continue
		}
		t.Automation.defaultInternalAutomationPolicy = &AutomationPolicy{
			IssuersRaw: []json.RawMessage{json.RawMessage(`{"module":"internal"}`)},
		}
		err = t.Automation.defaultInternalAutomationPolicy.Provision(t)
		if err != nil {
			return fmt.Errorf("provisioning default internal automation policy: %v", err)
		}
		break
	}
	for i, ap := range t.Automation.Policies {
		err := ap.Provision(t)
		if err != nil {
			return fmt.Errorf("provisioning automation policy %d: %v", i, err)
		}
	}

	// run replacer on ask URL (for environment variables) -- return errors to prevent surprises (#5036)
	if t.Automation != nil && t.Automation.OnDemand != nil && t.Automation.OnDemand.Ask != "" {
		t.Automation.OnDemand.Ask, err = repl.ReplaceOrErr(t.Automation.OnDemand.Ask, true, true)
		if err != nil {
			return fmt.Errorf("preparing 'ask' endpoint: %v", err)
		}
		perm := PermissionByHTTP{
			Endpoint: t.Automation.OnDemand.Ask,
		}
		if err := perm.Provision(ctx); err != nil {
			return fmt.Errorf("provisioning 'ask' module: %v", err)
		}
		t.Automation.OnDemand.permission = perm
	}

View on GitHub (pinned to 50e54ee279)

Solutions

  1. The wrapped error names the exact sub-failure; fix that first (it is usually more specific than this message)
  2. The index %d refers to the position in automation.policies — count from 0 to find the offending policy
  3. Validate subjects are legal DNS names (use punycode for unicode, avoid underscores)
  4. Run 'caddy validate' — provisioning errors surface at validation time, before Start

Example fix

// before
{"policies": [{"subjects": ["exa_mple.com"], "issuers": [{"module": "acme"}]}]}
// after
{"policies": [{"subjects": ["example.com"], "issuers": [{"module": "acme"}]}]}
Defensive patterns

Strategy: validation

Validate before calling

import "github.com/miekg/dns"

func validSubject(s string) bool {
	_, ok := dns.IsDomainName(s)
	return ok && !strings.Contains(s, "_")
}

Prevention

When it happens

Trigger: A subject like 'exa_mple.com' or invalid unicode that fails idna.ToASCII; an issuers entry with a bad module name or invalid fields (e.g. acme issuer with malformed ca URL); a managers entry whose plugin is not compiled in; policy storage module misconfiguration.

Common situations: Hand-written policy subjects with underscores or wildcards in the wrong position; typo'd issuer modules; plugin version drift after Caddy upgrades; DN-ish names or non-DNS strings in subjects.

Related errors


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