{"record":{"id":"b315768e0a290ec0","repo":"caddyserver/caddy","slug":"loading-on-demand-tls-permission-module-v","errorCode":null,"errorMessage":"loading on-demand TLS permission module: %v","messagePattern":"loading on-demand TLS permission module: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddytls/tls.go","lineNumber":284,"sourceCode":"\t\t\treturn fmt.Errorf(\"loading certificates: %v\", err)\n\t\t}\n\t\tfor _, cert := range certs {\n\t\t\thash, err := magic.CacheUnmanagedTLSCertificate(ctx, cert.Certificate, cert.Tags)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"caching unmanaged certificate: %v\", err)\n\t\t\t}\n\t\t\tt.loaded[hash] = \"\"\n\t\t}\n\t}\n\n\t// on-demand permission module\n\tif t.Automation != nil && t.Automation.OnDemand != nil && t.Automation.OnDemand.PermissionRaw != nil {\n\t\tif t.Automation.OnDemand.Ask != \"\" {\n\t\t\treturn 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\")\n\t\t}\n\t\tval, err := ctx.LoadModule(t.Automation.OnDemand, \"PermissionRaw\")\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"loading on-demand TLS permission module: %v\", err)\n\t\t}\n\t\tt.Automation.OnDemand.permission = val.(OnDemandPermission)\n\t}\n\n\t// automation/management policies\n\tif t.Automation == nil {\n\t\tt.Automation = new(AutomationConfig)\n\t}\n\tt.Automation.defaultPublicAutomationPolicy = new(AutomationPolicy)\n\terr = t.Automation.defaultPublicAutomationPolicy.Provision(t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"provisioning default public automation policy: %v\", err)\n\t}\n\tfor n := range t.automateNames {\n\t\t// if any names specified by the \"automate\" loader do not qualify for a public\n\t\t// certificate, we should initialize a default internal automation policy\n\t\t// (but we don't want to do this unnecessarily, since it may prompt for password!)\n\t\tif certmagic.SubjectQualifiesForPublicCert(n) {","sourceCodeStart":266,"sourceCodeEnd":302,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddytls/tls.go#L266-L302","documentation":"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.","triggerScenarios":"{\"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.","commonSituations":"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.","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"],"exampleFix":"// before\n\"permission\": {\"module\": \"http\", \"endpoint\": \"localhost:5555/check\"}\n// after\n\"permission\": {\"module\": \"http\", \"endpoint\": \"http://localhost:5555/check\"}","handlingStrategy":"validation","validationCode":"u, err := url.Parse(onDemandPermissionEndpoint)\nif err != nil || u.Scheme == \"\" || u.Host == \"\" {\n\treturn fmt.Errorf(\"permission endpoint must be absolute URL\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use absolute URLs for the http permission endpoint","Validate config with 'caddy validate' after changing on-demand settings"],"tags":["caddy","tls","on-demand","module-loading","permission"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}