{"record":{"id":"3a09e979e8255539","repo":"caddyserver/caddy","slug":"loading-packet-conn-wrapper-modules-v","errorCode":null,"errorMessage":"loading packet conn wrapper modules: %v","messagePattern":"loading packet conn wrapper modules: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddyhttp/app.go","lineNumber":357,"sourceCode":"\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\n\t\t\t// absent, prepend it so all defined wrappers come after the TLS\n\t\t\t// handshake; this simplifies logic when starting the server, since we\n\t\t\t// can simply assume the TLS placeholder will always be there\n\t\t\tif !hasTLSPlaceholder && len(srv.listenerWrappers) > 0 {\n\t\t\t\tsrv.listenerWrappers = append([]caddy.ListenerWrapper{new(tlsPlaceholderWrapper)}, srv.listenerWrappers...)\n\t\t\t}\n\t\t}\n\n\t\t// set up each packet conn modifier\n\t\tif srv.PacketConnWrappersRaw != nil {\n\t\t\tvals, err := ctx.LoadModule(srv, \"PacketConnWrappersRaw\")\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"loading packet conn wrapper modules: %v\", err)\n\t\t\t}\n\t\t\t// if any wrappers were configured, they come before the QUIC handshake;\n\t\t\t// unlike TLS above, there is no QUIC placeholder\n\t\t\tfor _, val := range vals.([]any) {\n\t\t\t\tsrv.packetConnWrappers = append(srv.packetConnWrappers, val.(caddy.PacketConnWrapper))\n\t\t\t}\n\t\t}\n\n\t\t// pre-compile the primary handler chain, and be sure to wrap it in our\n\t\t// route handler so that important security checks are done, etc.\n\t\tprimaryRoute := emptyHandler\n\t\tif srv.Routes != nil {\n\t\t\terr := srv.Routes.ProvisionHandlers(ctx, app.Metrics)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"server %s: setting up route handlers: %v\", srvName, err)\n\t\t\t}\n\t\t\tprimaryRoute = srv.Routes.Compile(emptyHandler)\n\t\t}","sourceCodeStart":339,"sourceCodeEnd":375,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddyhttp/app.go#L339-L375","documentation":"ctx.LoadModule instantiates servers.<name>.packet_conn_wrappers (modules implementing caddy.PacketConnWrapper, which wrap UDP/QUIC sockets before the QUIC handshake). Any unregistered module ID or failing Provision aborts app provisioning. There is no QUIC placeholder wrapper, unlike the TLS chain.","triggerScenarios":"A packet_conn_wrappers entry referencing a module not compiled into the binary, a typo'd module ID, or a wrapper whose own provisioning fails on its options.","commonSituations":"Using QUIC/HTTP/3 with a custom packet-filtering plugin that is missing from the build; copying configs between builds with different plugins.","solutions":["Check the wrapped error for the module name or option at fault","Build with the required plugin (xcaddy build --with ...) or drop the entry","Confirm the module actually implements PacketConnWrapper, not ListenerWrapper"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// ensure the module is compiled in before load\nout, _ := exec.Command(\"caddy\", \"list-modules\").Output()\nfor _, w := range srvCfg.PacketConnWrappersRaw {\n    id := gjson.GetBytes(w, \"wrapper\").String()\n    if !strings.Contains(string(out), id) {\n        return fmt.Errorf(\"packet conn wrapper %q missing from build\", id)\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Document packet_conn_wrappers plugin requirements in the repo README","Validate config in the target container image, not on a dev machine with different plugins"],"tags":["caddy","modules","quic","udp","plugins"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}