{"record":{"id":"b3994103570491da","repo":"caddyserver/caddy","slug":"loading-listener-wrapper-modules-v","errorCode":null,"errorMessage":"loading listener wrapper modules: %v","messagePattern":"loading listener wrapper modules: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddyhttp/app.go","lineNumber":326,"sourceCode":"\t\t}\n\t\tif err := srv.provisionDotHeaders(); err != nil {\n\t\t\treturn fmt.Errorf(\"server %s: %v\", srvName, err)\n\t\t}\n\n\t\t// process each listener address\n\t\tfor i := range srv.Listen {\n\t\t\tlnOut, err := repl.ReplaceOrErr(srv.Listen[i], true, true)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"server %s, listener %d: %v\", srvName, i, err)\n\t\t\t}\n\t\t\tsrv.Listen[i] = lnOut\n\t\t}\n\n\t\t// set up each listener modifier\n\t\tif srv.ListenerWrappersRaw != nil {\n\t\t\tvals, err := ctx.LoadModule(srv, \"ListenerWrappersRaw\")\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"loading listener wrapper modules: %v\", err)\n\t\t\t}\n\t\t\tvar hasTLSPlaceholder bool\n\t\t\tfor i, val := range vals.([]any) {\n\t\t\t\tif _, ok := val.(*tlsPlaceholderWrapper); ok {\n\t\t\t\t\tif i == 0 {\n\t\t\t\t\t\t// putting the tls placeholder wrapper first is nonsensical because\n\t\t\t\t\t\t// that is the default, implicit setting: without it, all wrappers\n\t\t\t\t\t\t// will go after the TLS listener anyway\n\t\t\t\t\t\treturn fmt.Errorf(\"it is unnecessary to specify the TLS listener wrapper in the first position because that is the default\")\n\t\t\t\t\t}\n\t\t\t\t\tif hasTLSPlaceholder {\n\t\t\t\t\t\treturn fmt.Errorf(\"TLS listener wrapper can only be specified once\")\n\t\t\t\t\t}\n\t\t\t\t\thasTLSPlaceholder = true\n\t\t\t\t}\n\t\t\t\tsrv.listenerWrappers = append(srv.listenerWrappers, val.(caddy.ListenerWrapper))\n\t\t\t}\n\t\t\t// if any wrappers were configured but the TLS placeholder wrapper is","sourceCodeStart":308,"sourceCodeEnd":344,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddyhttp/app.go#L308-L344","documentation":"ctx.LoadModule deserializes and instantiates each module in servers.<name>.listener_wrappers. If the raw JSON for any wrapper is not a registered caddy.ListenerWrapper module, or the module's own provisioning fails, the whole app fails to provision. The %v is the underlying module-loading error.","triggerScenarios":"Referencing an unregistered listener wrapper module ID (e.g. from a plugin binary not compiled in), a typo in the module name, or a valid wrapper whose Provision returns an error (bad option values).","commonSituations":"Using a custom build (xcaddy) that omits a plugin referenced in JSON config; copying configs between Caddy builds with different plugin sets; option name changes across plugin versions.","solutions":["Read the wrapped error: it names the module or field that failed","Ensure the wrapper plugin is compiled into your binary (xcaddy build with the plugin) or remove it from the config","Verify the module ID matches the plugin docs exactly (e.g. caddy.listeners.*.*)"],"exampleFix":"// before\n\"listener_wrappers\": [{\"wrapper\":\"proxy_protocol\"}]  // plugin missing\n// after\nxcaddy build --with github.com/mholt/caddy-l4  # then keep config","handlingStrategy":"validation","validationCode":"// verify each listener wrapper module is registered in this build\nids := caddy.ModulesModuleIDs() // or `caddy list-modules` from CLI\nfor _, w := range srvCfg.ListenerWrappersRaw {\n    name := gjson.GetBytes(w, \"wrapper\").String()\n    if !slices.Contains(ids, \"caddy.listeners.\"+name) && !slices.Contains(ids, name) {\n        return fmt.Errorf(\"listener wrapper %q not in build\", name)\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pin and document the exact xcaddy build (plugins + versions) next to the config","Run `caddy list-modules` after rebuilding and diff against required modules","Adapt+validate configs in the same container image that will run them"],"tags":["caddy","modules","listener","plugins","config"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}