{"record":{"id":"b3e72598fce9de0d","repo":"gofiber/fiber","slug":"proxy-nil-client-override-passed-to-do-forward","errorCode":null,"errorMessage":"proxy: nil client override passed to Do/Forward","messagePattern":"proxy: nil client override passed to Do/Forward","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"middleware/proxy/proxy.go","lineNumber":148,"sourceCode":"\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\t// Return nil to end proxying if no error\n\t\treturn nil\n\t}\n}\n\nvar defaultClient = &fasthttp.Client{\n\tNoDefaultUserAgentHeader: true,\n\tDisablePathNormalizing:   true,\n\tMaxConnsPerHost:          defaultMaxConnsPerHost,\n}\n\nvar client atomic.Pointer[fasthttp.Client]\n\nvar (\n\terrNilProxyClientOverride = errors.New(\"proxy: nil client override passed to Do/Forward\")\n\terrNilGlobalProxyClient   = errors.New(\"proxy: global client is nil, set a non-nil client with proxy.WithClient\")\n)\n\n// guardedConfigureClient composes a client's optional pre-existing\n// ConfigureClient hook with the dial-time SSRF guard. It is installed on a\n// *fasthttp.Client as the bound method value (&guardedConfigureClient{…}).run,\n// which fasthttp calls once per HostClient it creates — so the guard is\n// present before the first dial to each host and covers both the Dial and\n// DialTimeout code paths.\n//\n// The bound method's code pointer is stable across receivers (unlike a\n// closure's), so ensureClientGuarded recognizes an already-guarded client by\n// identity — no package-level map keyed by the client, which would pin the\n// client and its connection pool for the process lifetime. The struct is\n// referenced only from the client's own ConfigureClient field, so it is\n// collected together with the client.\ntype guardedConfigureClient struct {\n\t// orig is the caller's ConfigureClient hook, or nil. It runs before the","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/gofiber/fiber/blob/a105acad6c1e4576a77f01e02973f67e962bb58d/middleware/proxy/proxy.go#L130-L166","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","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."],"exampleFix":"// before\nvar cli *fasthttp.Client\nproxy.Do(c, url, cli) // nil override -> error\n// after\nif cli != nil {\n    proxy.Do(c, url, cli)\n} else {\n    proxy.Do(c, url)\n}","handlingStrategy":"validation","validationCode":"if cli != nil {\n    proxy.Do(c, url, cli)\n} else {\n    proxy.Do(c, url)\n}","typeGuard":null,"tryCatchPattern":"if err := proxy.Do(c, url, override...); err != nil {\n    if errors.Is(err, proxy.ErrNilClientOverride) /* unexported: match by message */ {\n        // call again without the nil override\n    }\n}","preventionTips":["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."],"tags":["proxy","config","nil-check"],"backgroundTag":null,"analyzedSha":"a105acad6c1e4576a77f01e02973f67e962bb58d","analyzedAt":"2026-08-11T17:33:26.942Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}