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

  1. Use a module whose ID is under the caddy.http.transport.proxy / network proxy namespace — currently from: "url" (legacy_forward also exists)
  2. Verify with `caddy list-modules` that the module you reference actually produces proxy functions
  3. 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

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


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/2b00abf47de89534. Report an issue: GitHub.