caddyserver/caddy · error
network_proxy module is not `(func(*http.Request) (*url.URL,
Error message
network_proxy module is not `(func(*http.Request) (*url.URL, error))``
What it means
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.
Source
Thrown at modules/caddyhttp/reverseproxy/httptransport.go:384
return conn, nil
}
// negotiate any HTTP/SOCKS proxy for the HTTP transport
proxy := http.ProxyFromEnvironment
if h.ForwardProxyURL != "" {
caddyCtx.Logger().Warn("forward_proxy_url is deprecated; use network_proxy instead")
u := network.ProxyFromURL{URL: h.ForwardProxyURL}
h.NetworkProxyRaw = caddyconfig.JSONModuleObject(u, "from", "url", nil)
}
if len(h.NetworkProxyRaw) != 0 {
proxyMod, err := caddyCtx.LoadModule(h, "NetworkProxyRaw")
if err != nil {
return nil, fmt.Errorf("failed to load network_proxy module: %v", err)
}
if m, ok := proxyMod.(caddy.ProxyFuncProducer); ok {
proxy = m.ProxyFunc()
} else {
return nil, fmt.Errorf("network_proxy module is not `(func(*http.Request) (*url.URL, error))``")
}
}
// we need to keep track if a proxy is used for a request
proxyWrapper := func(req *http.Request) (*url.URL, error) {
if proxy == nil {
return nil, nil
}
u, err := proxy(req)
if u == nil || err != nil {
return u, err
}
// there must be a proxy for this request
caddyhttp.SetVar(req.Context(), proxyVarKey, u)
return u, nil
}
rt := &http.Transport{
Proxy: proxyWrapper,View on GitHub (pinned to 50e54ee279)
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
Example fix
// JSON before
"network_proxy": {"from": "file"}
// JSON after
"network_proxy": {"from": "url", "url": "socks5://proxy.internal:1080"} Defensive patterns
Strategy: type-guard
Type guard
// compile-time guard used by Caddy itself; replicate in custom modules
var _ caddy.ProxyFuncProducer = (*MyProxy)(nil)
// runtime guard when loading
if _, ok := mod.(caddy.ProxyFuncProducer); !ok {
return errors.New("network_proxy module lacks ProxyFunc")
} Prevention
- Only reference modules from the proxy namespace in network_proxy
- Add the ProxyFuncProducer interface guard to any custom proxy module
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- failed to load network_proxy module: %v
- unsupported HTTP version: %s, supported version: %s
- local_address must be a single address, not a port range
- local_address must be a TCP address, not a UDP address
- unsupported network
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/2b00abf47de89534.
Report an issue: GitHub.