gofiber/fiber · error
Servers cannot be empty
Error message
Servers cannot be empty
What it means
BalancerForward requires at least one upstream server in its servers slice; passing an empty slice (or nil) is treated as a programmer error and panics with "Servers cannot be empty". This is a distinct, earlier guard from the per-server validateUpstream loop that follows it.
Solutions
- Guard len(servers) > 0 before calling BalancerForward, and fail configuration loudly when the list is empty.
- Ensure config sources require at least one entry at load time.
Example fix
// before
servers := discovery.GetUpstreams() // []string{} when discovery is empty
app.BalancerForward(servers) // panics
// after
servers := discovery.GetUpstreams()
if len(servers) == 0 {
log.Fatal("no upstreams discovered")
}
app.BalancerForward(servers) Defensive patterns
Strategy: validation
Validate before calling
func mustBalancerForward(servers []string) fiber.Handler {
if len(servers) == 0 {
log.Fatal("BalancerForward requires at least one server")
}
return proxy.BalancerForward(servers)
} Type guard
func hasServers(servers []string) bool { return len(servers) > 0 } Prevention
- Never pass a discovery/config slice directly to BalancerForward without a length check.
- Fail configuration loudly when the upstream list is empty rather than crashing inside the handler.
When it happens
Trigger: app.BalancerForward([]string{}), or app.BalancerForward(nil), or app.BalancerForward(servers) where servers was filtered down to zero elements.
Common situations: A dynamic server list sourced from service discovery or config that came back empty; a strings.Split on an empty env var yielding [""] that was then filtered to []; a test that forgot to populate the slice.
Related errors
- ErrUpstreamHostBlocked
- ErrUpstreamHostInvalid
- proxy: WithClient requires a non-nil *fasthttp.Client
- add: invalid http method
- client: invalid proxy URL
AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11).
Data as JSON: /api/errors/14785e10e290abfe.
Report an issue: GitHub.
Appendix: source
Thrown at middleware/proxy/proxy.go:654
return r.pool[index]
}
}
}
// BalancerForward Forward performs the given http request with round robin algorithm to server and fills the given http response.
// This method will return a fiber.Handler.
//
// As with DomainForward, every server is parsed and policy-checked at
// handler construction. A misconfigured entry panics at startup.
//
// SSRF note: despite the name, this helper dispatches through the
// shared/user-supplied client rather than a Balancer HostClient, but it
// gets the same protection as Do — up-front host validation plus the
// dial-time validated-IP guard on the dispatching client when
// AllowPrivateIPs is false.
func BalancerForward(servers []string, clients ...*fasthttp.Client) fiber.Handler {
if len(servers) == 0 {
panic("Servers cannot be empty")
}
policy := currentSecurityPolicy()
bases := make([]*url.URL, len(servers))
for i, s := range servers {
base, err := validateUpstream(s, policy)
if err != nil {
panic(err)
}
bases[i] = base
}
r := &urlRoundrobin{pool: bases}
return func(c fiber.Ctx) error {
base := r.get()
setRealIP(c)
return doActionWithPolicy(c, joinUpstreamPath(base, c.OriginalURL()), currentSecurityPolicy(),
func(cli *fasthttp.Client, req *fasthttp.Request, resp *fasthttp.Response, _ *url.URL) error {
return cli.Do(req, resp)
}, clients...)View on GitHub (pinned to a105acad6c)