{"record":{"id":"05c9915d2129b842","repo":"caddyserver/caddy","slug":"loading-certificate-loader-modules-s","errorCode":null,"errorMessage":"loading certificate loader modules: %s","messagePattern":"loading certificate loader modules: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddytls/tls.go","lineNumber":225,"sourceCode":"\tif t.Cache != nil {\n\t\tcacheOpts.Capacity = t.Cache.Capacity\n\t}\n\tif cacheOpts.Capacity <= 0 {\n\t\tcacheOpts.Capacity = 10000\n\t}\n\n\tcertCacheMu.Lock()\n\tif certCache == nil {\n\t\tcertCache = certmagic.NewCache(cacheOpts)\n\t} else {\n\t\tcertCache.SetOptions(cacheOpts)\n\t}\n\tcertCacheMu.Unlock()\n\n\t// certificate loaders\n\tval, err := ctx.LoadModule(t, \"CertificatesRaw\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"loading certificate loader modules: %s\", err)\n\t}\n\tfor modName, modIface := range val.(map[string]any) {\n\t\tif modName == \"automate\" {\n\t\t\t// special case; these will be loaded in later using our automation facilities,\n\t\t\t// which we want to avoid doing during provisioning\n\t\t\tif automateNames, ok := modIface.(*AutomateLoader); ok && automateNames != nil {\n\t\t\t\tif t.automateNames == nil {\n\t\t\t\t\tt.automateNames = make(map[string]struct{})\n\t\t\t\t}\n\t\t\t\trepl := caddy.NewReplacer()\n\t\t\t\tfor _, sub := range *automateNames {\n\t\t\t\t\tt.automateNames[repl.ReplaceAll(sub, \"\")] = struct{}{}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn fmt.Errorf(\"loading certificates with 'automate' requires array of strings, got: %T\", modIface)\n\t\t\t}\n\t\t\tcontinue\n\t\t}","sourceCodeStart":207,"sourceCodeEnd":243,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddytls/tls.go#L207-L243","documentation":"Thrown when ctx.LoadModule(t, \"CertificatesRaw\") fails while provisioning the tls app's 'certificates' section. CertificatesRaw is a map of loader-name -> module config (loaders such as load_files, load_folders, automate). The load fails for any entry whose module name is unknown, whose inline JSON is malformed for the loader, or whose own Provision returns an error.","triggerScenarios":"Configuring tls.certificates with an invalid loader key, e.g. {\"certificates\": {\"load_file\": [...]}} (singular, nonexistent) instead of \"load_files\"; wrong array/object shape for load_files entries (missing 'certificate'/'key' fields); a custom loader module not compiled in.","commonSituations":"Hand-written JSON configs with typos in loader names; Caddyfile 'tls /path/cert.pem /path/key.pem' translating to load_files with unreadable or misquoted paths; migrating configs between Caddy versions where loader schemas changed.","solutions":["Inspect the wrapped error: it names which loader entry failed and why","Use 'caddy adapt' (or 'caddy validate --config ... --adapter ...') to confirm the config adapts and the loader names match the docs (load_files, load_folders, automate)","Ensure each load_files entry has both 'certificate' and 'key' string fields with valid paths","For custom loaders, verify the module is registered via 'caddy list-modules'"],"exampleFix":"// before\n{\"apps\": {\"tls\": {\"certificates\": {\"load_file\": [{\"certificate\": \"/certs/a.pem\", \"key\": \"/certs/a.key\"}]}}}}\n// after\n{\"apps\": {\"tls\": {\"certificates\": {\"load_files\": [{\"certificate\": \"/certs/a.pem\", \"key\": \"/certs/a.key\"}]}}}}","handlingStrategy":"validation","validationCode":"caddy adapt --config Caddyfile --adapter caddyfile --pretty | jq '.apps.tls.certificates'\n# confirm only known loader keys: load_files, load_folders, automate","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer authoring Caddyfile syntax and adapting to JSON rather than hand-writing the certificates map","Validate configs in CI with 'caddy validate'"],"tags":["caddy","tls","certificates","module-loading","config"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}