caddyserver/caddy · error
loading on-demand TLS permission module: %v
Error message
loading on-demand TLS permission module: %v
What it means
When tls.automation.on_demand.permission is configured, ctx.LoadModule loads that permission module; failure to load or provision it produces this error. Causes: unknown module name under 'permission', module inline config rejected by the module's own Provision, or the module not being compiled into the binary.
Source
Thrown at modules/caddytls/tls.go:284
return fmt.Errorf("loading certificates: %v", err)
}
for _, cert := range certs {
hash, err := magic.CacheUnmanagedTLSCertificate(ctx, cert.Certificate, cert.Tags)
if err != nil {
return fmt.Errorf("caching unmanaged certificate: %v", err)
}
t.loaded[hash] = ""
}
}
// on-demand permission module
if t.Automation != nil && t.Automation.OnDemand != nil && t.Automation.OnDemand.PermissionRaw != nil {
if t.Automation.OnDemand.Ask != "" {
return fmt.Errorf("on-demand TLS config conflict: both 'ask' endpoint and a 'permission' module are specified; 'ask' is deprecated, so use only the permission module")
}
val, err := ctx.LoadModule(t.Automation.OnDemand, "PermissionRaw")
if err != nil {
return fmt.Errorf("loading on-demand TLS permission module: %v", err)
}
t.Automation.OnDemand.permission = val.(OnDemandPermission)
}
// automation/management policies
if t.Automation == nil {
t.Automation = new(AutomationConfig)
}
t.Automation.defaultPublicAutomationPolicy = new(AutomationPolicy)
err = t.Automation.defaultPublicAutomationPolicy.Provision(t)
if err != nil {
return fmt.Errorf("provisioning default public automation policy: %v", err)
}
for n := range t.automateNames {
// 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) {View on GitHub (pinned to 50e54ee279)
Solutions
- Read the wrapped error — it comes from the module's own loader/Provision
- For the built-in 'http' module, ensure endpoint is a fully-qualified URL with scheme and host
- Verify module availability with 'caddy list-modules | grep permission'
- Validate the config with 'caddy validate' before deploying
Example fix
// before
"permission": {"module": "http", "endpoint": "localhost:5555/check"}
// after
"permission": {"module": "http", "endpoint": "http://localhost:5555/check"} Defensive patterns
Strategy: validation
Validate before calling
u, err := url.Parse(onDemandPermissionEndpoint)
if err != nil || u.Scheme == "" || u.Host == "" {
return fmt.Errorf("permission endpoint must be absolute URL")
} Prevention
- Use absolute URLs for the http permission endpoint
- Validate config with 'caddy validate' after changing on-demand settings
When it happens
Trigger: {"permission": {"module": "http", "endpoint": "not a valid url"}} — the http permission module validates its endpoint and fails; or a custom permission module name that is not registered; or a nil/empty module object.
Common situations: Typos in the endpoint URL (missing scheme, spaces); forgetting that the permission module shape is {module: name, ...options}; using a plugin not included in the build.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- loading overall DNS provider module: %v
- loading certificate loader modules: %s
- on-demand TLS config conflict: both 'ask' endpoint and a 'pe
- preparing 'ask' endpoint: %v
- provisioning 'ask' module: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/b315768e0a290ec0.
Report an issue: GitHub.