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

  1. Pass a non-empty slice of server URLs, e.g. []string{"http://node1:8080", "http://node2:8080"}.
  2. Guard the call: only register the BalancerForward handler when the servers slice is non-empty.
  3. 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

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


AI-assisted analysis of gofiber/fiber@9a4c7e57fe (2026-08-04). Data as JSON: /data/errors/14785e10e290abfe.json. Report an issue: GitHub.