{"record":{"id":"2b00abf47de89534","repo":"caddyserver/caddy","slug":"network-proxy-module-is-not-func-http-request","errorCode":null,"errorMessage":"network_proxy module is not `(func(*http.Request) (*url.URL, error))``","messagePattern":"network_proxy module is not `\\(func\\(\\*http\\.Request\\) \\(\\*url\\.URL, error\\)\\)``","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddyhttp/reverseproxy/httptransport.go","lineNumber":384,"sourceCode":"\t\treturn conn, nil\n\t}\n\n\t// negotiate any HTTP/SOCKS proxy for the HTTP transport\n\tproxy := http.ProxyFromEnvironment\n\tif h.ForwardProxyURL != \"\" {\n\t\tcaddyCtx.Logger().Warn(\"forward_proxy_url is deprecated; use network_proxy instead\")\n\t\tu := network.ProxyFromURL{URL: h.ForwardProxyURL}\n\t\th.NetworkProxyRaw = caddyconfig.JSONModuleObject(u, \"from\", \"url\", nil)\n\t}\n\tif len(h.NetworkProxyRaw) != 0 {\n\t\tproxyMod, err := caddyCtx.LoadModule(h, \"NetworkProxyRaw\")\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to load network_proxy module: %v\", err)\n\t\t}\n\t\tif m, ok := proxyMod.(caddy.ProxyFuncProducer); ok {\n\t\t\tproxy = m.ProxyFunc()\n\t\t} else {\n\t\t\treturn nil, fmt.Errorf(\"network_proxy module is not `(func(*http.Request) (*url.URL, error))``\")\n\t\t}\n\t}\n\t// we need to keep track if a proxy is used for a request\n\tproxyWrapper := func(req *http.Request) (*url.URL, error) {\n\t\tif proxy == nil {\n\t\t\treturn nil, nil\n\t\t}\n\t\tu, err := proxy(req)\n\t\tif u == nil || err != nil {\n\t\t\treturn u, err\n\t\t}\n\t\t// there must be a proxy for this request\n\t\tcaddyhttp.SetVar(req.Context(), proxyVarKey, u)\n\t\treturn u, nil\n\t}\n\n\trt := &http.Transport{\n\t\tProxy:                  proxyWrapper,","sourceCodeStart":366,"sourceCodeEnd":402,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddyhttp/reverseproxy/httptransport.go#L366-L402","documentation":"The network_proxy module loaded successfully but does not implement the `caddy.ProxyFuncProducer` interface (`ProxyFunc() func(*http.Request) (*url.URL, error)`). The transport requires this interface to obtain the per-request proxy URL, so it errors during NewTransport.","triggerScenarios":"Pointing network_proxy at a module in the wrong namespace — one that is a valid Caddy module but not a network proxy producer (e.g. a TLS issuer or compression module ID).","commonSituations":"Hand-written JSON where the module \"from\" value is a valid module ID from a completely different module family; copy-paste of module JSON blocks between config sections.","solutions":["Use a module whose ID is under the caddy.http.transport.proxy / network proxy namespace — currently from: \"url\" (legacy_forward also exists)","Verify with `caddy list-modules` that the module you reference actually produces proxy functions","Prefer the Caddyfile `forward_proxy_url` or network_proxy syntax so the adapter picks the correct module"],"exampleFix":"// JSON before\n\"network_proxy\": {\"from\": \"file\"}\n// JSON after\n\"network_proxy\": {\"from\": \"url\", \"url\": \"socks5://proxy.internal:1080\"}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"// compile-time guard used by Caddy itself; replicate in custom modules\nvar _ caddy.ProxyFuncProducer = (*MyProxy)(nil)\n\n// runtime guard when loading\nif _, ok := mod.(caddy.ProxyFuncProducer); !ok {\n\treturn errors.New(\"network_proxy module lacks ProxyFunc\")\n}","tryCatchPattern":null,"preventionTips":["Only reference modules from the proxy namespace in network_proxy","Add the ProxyFuncProducer interface guard to any custom proxy module"],"tags":["reverse-proxy","http-transport","modules","interface"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}