grpc/grpc-go · error

bad resolver state

Error message

bad resolver state

What it means

Thrown when the *anypb.Any override payload fails to unmarshal into *rpb.RBACPerRoute via UnmarshalTo. This means the type_url and/or the serialized bytes inside the Any do not correspond to a valid RBACPerRoute proto message — the wire payload is corrupt, truncated, or contains a different message type than advertised.

Solutions

  1. Verify the Any's type_url is exactly type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBACPerRoute and the payload bytes are a serialized RBACPerRoute (which wraps an RBAC message in its 'rbac' field), not a bare RBAC.
  2. Align the go-control-plane version used by the control plane with the one linked into grpc-go on the client so the proto schemas match.
  3. Capture the full DiscoveryResponse from the control plane (e.g., via GRPC_XDS_DEBUG_V3=log) and validate the bytes deserialize standalone with protoc --decode_raw.

Example fix

// before: control plane puts a bare RBAC into the per-route override
override_any, _ := anypb.New(&v3rbacpb.RBAC{Rules: rules})

// after: wrap it in RBACPerRoute as the schema requires
override_any, _ := anypb.New(&rpb.RBACPerRoute{Rbac: &v3rbacpb.RBAC{Rules: rules}})
Defensive patterns

Strategy: validation

Validate before calling

// Validate the Any can unmarshal into RBACPerRoute before calling ParseFilterConfigOverride:
func validateRBACOverride(any *anypb.Any) error {
    expectedURL := "type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBACPerRoute"
    if any.TypeUrl != expectedURL {
        return fmt.Errorf("type_url mismatch: want %s, got %s", expectedURL, any.TypeUrl)
    }
    msg := new(rpb.RBACPerRoute)
    if err := any.UnmarshalTo(msg); err != nil {
        return fmt.Errorf("payload does not unmarshal to RBACPerRoute: %w", err)
    }
    return nil
}

Try / catch

// When constructing the chain engine from xDS, catch unmarshal failures and NACK:
cfg, err := b.ParseFilterConfigOverride(overrideAny)
if err != nil {
    return fmt.Errorf("rejecting xDS resource: RBAC override parse failed: %w", err)
}

Prevention

When it happens

Trigger: The Any's type_url is set to RBACPerRoute but the bytes were serialized from a different proto (e.g., an RBAC message instead of RBACPerRoute). A truncated or corrupted protobuf payload reaching the filter after a buggy control-plane serialization. A schema version mismatch where the control plane serializes a newer RBACPerRoute field layout that the client's go-control-plane version cannot decode.

Common situations: Upgrading Envoy/go-control-plane on the control plane to a version that added new required fields to RBACPerRoute without upgrading grpc-go on the data plane. A network-level or serialization-level corruption of the LDS/RDS DiscoveryResponse. A control plane that mistakenly puts an RBAC (not RBACPerRoute) message inside the per-route override Any.

Related errors


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

Appendix: source

Thrown at balancer/balancer.go:394

type ExitIdler interface {
	// ExitIdle instructs the LB policy to reconnect to backends / exit the
	// IDLE state, if appropriate and possible.  Note that SubConns that enter
	// the IDLE state will not reconnect until SubConn.Connect is called.
	ExitIdle()
}

// ClientConnState describes the state of a ClientConn relevant to the
// balancer.
type ClientConnState struct {
	ResolverState resolver.State
	// The parsed load balancing configuration returned by the builder's
	// ParseConfig method, if implemented.
	BalancerConfig serviceconfig.LoadBalancingConfig
}

// ErrBadResolverState may be returned by UpdateClientConnState to indicate a
// problem with the provided name resolver data.
var ErrBadResolverState = errors.New("bad resolver state")

View on GitHub (pinned to 0c51461d27)