gofiber/fiber · error
proxy: nil client override passed to Do/Forward
Error message
proxy: nil client override passed to Do/Forward
What it means
Returned by middleware/proxy.selectClient when a per-call client override is passed as the first variadic argument but is nil. Do, Forward, and DomainForward accept an optional *fasthttp.Client override; passing nil explicitly is treated as a programming error (distinct from passing no override at all, which falls back to the global client). The error is unexported, returned from the proxy action.
Solutions
- Omit the clients argument entirely to use the global/default client: proxy.Do(c, url).
- Ensure any variable passed as the override is non-nil before the call.
- If you need a default when your variable is nil, pass nothing rather than nil: wrap with an if.
- Set a global client with proxy.WithClient if you want all calls to share one.
Example fix
// before
var cli *fasthttp.Client
proxy.Do(c, url, cli) // nil override -> error
// after
if cli != nil {
proxy.Do(c, url, cli)
} else {
proxy.Do(c, url)
} Defensive patterns
Strategy: validation
Validate before calling
if cli != nil {
proxy.Do(c, url, cli)
} else {
proxy.Do(c, url)
} Try / catch
if err := proxy.Do(c, url, override...); err != nil {
if errors.Is(err, proxy.ErrNilClientOverride) /* unexported: match by message */ {
// call again without the nil override
}
} Prevention
- Pass no variadic client when you want the default; do not pass nil.
- Guard nil client variables before forwarding them into Do/Forward/DomainForward.
- Set a global client with proxy.WithClient to share one across calls.
When it happens
Trigger: Calling proxy.Do(c, url, nil) / proxy.Forward(url, nil) / proxy.DomainForward(host, addr, nil) with a literal nil as the clients variadic. A nil pointer variable passed in the same slot also triggers it.
Common situations: A conditional client variable left nil and forwarded into the call; refactoring that changed a client argument from required to variadic; passing nil to mean 'use default' (the API expects omission for that).
Related errors
- client: invalid proxy URL
- ErrUpstreamHostBlocked
- ErrUpstreamHostInvalid
- ErrUpstreamHostInvalid
- ErrUpstreamSchemeNotAllowed
AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11).
Data as JSON: /api/errors/b3e72598fce9de0d.
Report an issue: GitHub.
Appendix: source
Thrown at middleware/proxy/proxy.go:148
return err
}
}
// Return nil to end proxying if no error
return nil
}
}
var defaultClient = &fasthttp.Client{
NoDefaultUserAgentHeader: true,
DisablePathNormalizing: true,
MaxConnsPerHost: defaultMaxConnsPerHost,
}
var client atomic.Pointer[fasthttp.Client]
var (
errNilProxyClientOverride = errors.New("proxy: nil client override passed to Do/Forward")
errNilGlobalProxyClient = errors.New("proxy: global client is nil, set a non-nil client with proxy.WithClient")
)
// guardedConfigureClient composes a client's optional pre-existing
// ConfigureClient hook with the dial-time SSRF guard. It is installed on a
// *fasthttp.Client as the bound method value (&guardedConfigureClient{…}).run,
// which fasthttp calls once per HostClient it creates — so the guard is
// present before the first dial to each host and covers both the Dial and
// DialTimeout code paths.
//
// The bound method's code pointer is stable across receivers (unlike a
// closure's), so ensureClientGuarded recognizes an already-guarded client by
// identity — no package-level map keyed by the client, which would pin the
// client and its connection pool for the process lifetime. The struct is
// referenced only from the client's own ConfigureClient field, so it is
// collected together with the client.
type guardedConfigureClient struct {
// orig is the caller's ConfigureClient hook, or nil. It runs before theView on GitHub (pinned to a105acad6c)