grpc/grpc-go · error

produced zero addresses

Error message

produced zero addresses

What it means

Thrown by ParseFilterConfigOverride on the Router filter when a non-nil per-route override is provided. The gRPC Router filter is purely a marker/terminal filter — it does not support any per-route configuration overrides. Envoy's router filter has per-route options, but gRPC's implementation intentionally rejects them.

Source

Thrown at balancer/ringhash/ringhash.go:299

		}
		if idleBalancer != nil {
			idleBalancer.ExitIdle()
		}
	}

	if b.inhibitChildUpdates {
		return
	}

	// Update the channel.
	if b.endpointStates.Len() > 0 && b.shouldRegenerateRing {
		// with a non-empty list of endpoints.
		b.ring = newRing(b.endpointStates, b.config.MinRingSize, b.config.MaxRingSize, b.logger)
	}
	b.shouldRegenerateRing = false
	var newPicker balancer.Picker
	if b.endpointStates.Len() == 0 {
		newPicker = base.NewErrPicker(errors.New("produced zero addresses"))
	} else {
		newPicker = b.newPickerLocked()
	}
	b.ClientConn.UpdateState(balancer.State{
		ConnectivityState: state,
		Picker:            newPicker,
	})
}

func (b *ringhashBalancer) Close() {
	b.logger.Infof("Shutdown")
	b.child.Close()
}

func (b *ringhashBalancer) ExitIdle() {
	// ExitIdle implementation is a no-op because connections are either
	// triggers from picks or from child balancer state changes.
}

View on GitHub (pinned to 0c51461d27)

Solutions

  1. Remove the typed_per_filter_config entry for the router filter from the affected route(s) in the RouteConfiguration.
  2. If the control plane auto-generates per-filter-config for every filter, configure it to skip the router filter.
  3. Understand that gRPC routing (method matching, action selection) is handled by the resolver/config-selector, not by per-route router overrides.

Example fix

// before: RDS route with router override
route:
  typed_per_filter_config:
    "envoy.filters.http.router":
      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
      dynamic_stats: false

// after: remove the router override entirely
route:
  typed_per_filter_config: {}
Defensive patterns

Strategy: validation

Validate before calling

// Strip router per-route overrides before sending RDS to the data plane:
for _, vh := range routeConfig.GetVirtualHosts() {
    for _, route := range vh.GetRoutes() {
        cfg := route.GetTypedPerFilterConfig()
        for k := range cfg {
            if strings.Contains(k, "router") {
                delete(cfg, k)
            }
        }
    }
}

Prevention

When it happens

Trigger: A RouteConfiguration route entry includes a typed_per_filter_config key for the router filter (e.g., envoy.extensions.filters.http.router.v3.Router) with a non-nil override. The xdsclient passes this override to the router builder, which does not expect one.

Common situations: An EnvoyFilter or route configuration template that was copied from a full Envoy deployment where router per-route overrides (like rewrite settings) are used, then applied to a gRPC xDS setup. A control plane that generically populates typed_per_filter_config for all listed filters. A misunderstanding that gRPC's router filter supports the same per-route config as Envoy's.

Related errors


AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11). Data as JSON: /api/errors/25ba40703aa50305. Report an issue: GitHub.