labstack/echo · error

echo proxy middleware requires balancer

Error message

echo proxy middleware requires balancer

What it means

Returned by ProxyConfig.ToMiddleware when config.Balancer is nil. The proxy middleware forwards each request to a target chosen by the balancer; without one there is no target-selection strategy. Build a balancer with NewRoundRobinBalancer or NewRandomBalancer from a list of *ProxyTarget.

Source

Thrown at middleware/proxy.go:314

}

// ProxyWithConfig returns a Proxy middleware or panics if configuration is invalid.
//
// Proxy middleware forwards the request to upstream server using a configured load balancing technique.
func ProxyWithConfig(config ProxyConfig) echo.MiddlewareFunc {
	return toMiddlewareOrPanic(config)
}

// ToMiddleware converts ProxyConfig to middleware or returns an error for invalid configuration
func (config ProxyConfig) ToMiddleware() (echo.MiddlewareFunc, error) {
	if config.Skipper == nil {
		config.Skipper = DefaultProxyConfig.Skipper
	}
	if config.ContextKey == "" {
		config.ContextKey = DefaultProxyConfig.ContextKey
	}
	if config.Balancer == nil {
		return nil, errors.New("echo proxy middleware requires balancer")
	}
	if config.RetryFilter == nil {
		config.RetryFilter = func(c *echo.Context, e error) bool {
			if httpErr, ok := e.(*echo.HTTPError); ok {
				return httpErr.Code == http.StatusBadGateway
			}
			return false
		}
	}
	if config.ErrorHandler == nil {
		config.ErrorHandler = func(c *echo.Context, err error) error {
			return err
		}
	}

	if config.Rewrite != nil {
		if config.RegexRewrite == nil {
			config.RegexRewrite = make(map[*regexp.Regexp]string)

View on GitHub (pinned to 05489dc173)

Solutions

  1. Construct a balancer: middleware.NewRoundRobinBalancer([]*middleware.ProxyTarget{{URL: mustParseURL("http://upstream:8080")}}) and set it as config.Balancer.
  2. Prefer the shorthand Proxy(balancer) when you only need a balancer.
  3. Fail fast at startup if the targets list is empty rather than passing a nil balancer.
  4. Use config.ToMiddleware() to get the error returned instead of panicked.

Example fix

// before
m := middleware.ProxyWithConfig(middleware.ProxyConfig{
    Rewrite: map[string]string{"/old/*": "/$1"},
})
// after
targets := []*middleware.ProxyTarget{{Name: "upstream", URL: mustParseURL("http://upstream:8080")}}
m := middleware.ProxyWithConfig(middleware.ProxyConfig{
    Balancer: middleware.NewRoundRobinBalancer(targets),
    Rewrite:  map[string]string{"/old/*": "/$1"},
})
Defensive patterns

Strategy: validation

Validate before calling

func proxyMiddleware(targets []*middleware.ProxyTarget) (echo.MiddlewareFunc, error) {
    if len(targets) == 0 {
        return nil, errors.New("proxy requires at least one target")
    }
    cfg := middleware.ProxyConfig{Balancer: middleware.NewRoundRobinBalancer(targets)}
    return cfg.ToMiddleware()
}

Prevention

When it happens

Trigger: Calling ProxyWithConfig(ProxyConfig{...}) without setting Balancer, or assigning a nil balancer variable (e.g., when the targets list is empty and you skip constructing one).

Common situations: Developer constructs the balancer conditionally based on env config and the branch leaves it nil; or migrates from Proxy(balancer) to ProxyWithConfig and forgets to carry Balancer over.

Related errors


AI-assisted analysis of labstack/echo@05489dc173 (2026-08-04). Data as JSON: /data/errors/1d6bc6de3673e96c.json. Report an issue: GitHub.