gofiber/fiber · error
Servers cannot be empty
Error message
Servers cannot be empty
What it means
proxy.BalancerForward constructs a round-robin handler from a list of server URLs and panics if the slice is empty, because there is no upstream to balance across. Each server is also parsed and policy-checked at construction, so a misconfigured entry panics here too.
Source
Thrown at middleware/proxy/proxy.go:633
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()
c.Request().Header.Set("X-Real-IP", c.IP())
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 9a4c7e57fe)
Solutions
- Pass a non-empty slice of server URLs, e.g. []string{"http://node1:8080", "http://node2:8080"}.
- Guard the call: only register the BalancerForward handler when the servers slice is non-empty.
- Validate service-discovery results and fail loudly in your bootstrap code before reaching BalancerForward.
Example fix
// before
app.Get("/proxy/*", proxy.BalancerForward(servers))
// after
if len(servers) == 0 {
log.Fatal("no upstream servers configured")
}
app.Get("/proxy/*", proxy.BalancerForward(servers)) Defensive patterns
Strategy: validation
Validate before calling
if len(servers) == 0 {
log.Fatal("proxy: BalancerForward requires at least one server")
}
app.Get("/proxy/*", proxy.BalancerForward(servers)) Prevention
- Validate service-discovery / config results for non-empty server lists at bootstrap.
- Fail loudly in startup code rather than letting an empty slice reach BalancerForward.
When it happens
Trigger: Calling proxy.BalancerForward([]string{}) or proxy.BalancerForward(nil) directly when wiring a route handler. Also triggered when the slice comes from config that resolved to empty.
Common situations: Loading backends from service discovery that returned an empty list at startup. Passing a slice built by filtering that removed all entries. Forgetting to populate the slice in a config struct.
Related errors
- Servers cannot be empty
- proxy: WithClient requires a non-nil *fasthttp.Client
- client: invalid proxy URL: %w
- favicon: file size exceeds max bytes %d
- route handler 'fn' cannot be nil
AI-assisted analysis of gofiber/fiber@9a4c7e57fe (2026-08-04).
Data as JSON: /data/errors/14785e10e290abfe.json.
Report an issue: GitHub.