grpc/grpc-go · error
no SubConn is available
Error message
no SubConn is available
What it means
Thrown by the RBAC HTTP filter builder's ParseFilterConfigOverride when the per-route override proto.Message passed by the xDS resolver is nil. The xDS HTTP filter framework requires every registered filter to handle overrides; the RBAC builder rejects nil outright rather than silently treating it as 'no override.' This prevents ambiguous state where a route reference is present in the LDS/RDS resource but carries no actual configuration payload.
Solutions
- Inspect the RDS resource for the route in question and confirm the http_filters per-filter-config entry for type envoy.extensions.filters.http.rbac.v3.RBACPerRoute has a non-nil typed_config with a valid type_url.
- If no per-route RBAC override is intended for that route, remove the RBACPerRoute entry from the route's typed_per_filter_config map entirely rather than leaving a nil placeholder.
- Upgrade the control plane and grpc-go to compatible xDS schema versions so the per-filter-config field is always populated with a well-formed Any.
Example fix
// before (control plane route config):
route:
typed_per_filter_config:
"envoy.filters.http.rbac":
// missing @type body -> nil Any -> error
// after:
route:
typed_per_filter_config:
"envoy.filters.http.rbac":
"@type": type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBACPerRoute
rbac:
rules:
action: ALLOW
policies:
allow-all:
permissions: [{any: true}]
principals: [{any: true}] Defensive patterns
Strategy: validation
Validate before calling
// Before calling the xDS filter pipeline, validate per-route override configs:
for routeName, route := range routeConfig.GetVirtualHosts()[0].GetRoutes() {
for filterName, cfg := range route.GetTypedPerFilterConfig() {
if strings.Contains(filterName, "rbac") && cfg == nil {
return fmt.Errorf("route %s has nil RBAC per-filter override", routeName)
}
if cfg != nil && cfg.TypeUrl == "" {
return fmt.Errorf("route %s RBAC override has empty type_url", routeName)
}
}
} Type guard
func isNonNilAny(msg proto.Message) bool {
if msg == nil {
return false
}
any, ok := msg.(*anypb.Any)
return ok && any != nil && any.TypeUrl != ""
} Prevention
- Never leave a typed_per_filter_config entry with a nil body; either populate it fully or omit the key.
- Validate all per-filter-config entries in RDS resources before applying them to the xDS client.
- Use a policy-as-code tool (OPA, CedAR) to reject xDS configs with incomplete per-route overrides at deployment time.
When it happens
Trigger: A control plane sends a RouteConfiguration (RDS) whose RouteAction references an RBACPerRoute typed per-filter-config entry, but the Any-wrapped message for that entry is nil or was stripped during proto marshalling. Also triggered if the xdsclient's unmarshalling code passes a nil override to httpfilter.ParseFilterConfigOverride due to a missing typed_config field in the per-filter-config map.
Common situations: Misconfigured Istio EnvoyFilter or Traffic Director route rule that specifies an RBAC per-route override key but omits the config body. Proto serialization round-trips that drop nil oneof fields. Control plane version mismatch where the per-filter-config schema expects a field the older client does not populate.
Related errors
- all SubConns are in TransientFailure
- bad resolver state
- grpc: credentials.Bundle may not be used with individual…
- grpc: no transport security set (use…
- grpc: the connection is closing
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/3ed93ab1495e18cd.
Report an issue: GitHub.
Appendix: source
Thrown at balancer/balancer.go:268
// Err is the rpc error the RPC finished with. It could be nil.
Err error
// Trailer contains the metadata from the RPC's trailer, if present.
Trailer metadata.MD
// BytesSent indicates if any bytes have been sent to the server.
BytesSent bool
// BytesReceived indicates if any byte has been received from the server.
BytesReceived bool
// ServerLoad is the load received from server. It's usually sent as part of
// trailing metadata.
//
// The only supported type now is *orca_v3.LoadReport.
ServerLoad any
}
var (
// ErrNoSubConnAvailable indicates no SubConn is available for pick().
// gRPC will block the RPC until a new picker is available via UpdateState().
ErrNoSubConnAvailable = errors.New("no SubConn is available")
// ErrTransientFailure indicates all SubConns are in TransientFailure.
// WaitForReady RPCs will block, non-WaitForReady RPCs will fail.
//
// Deprecated: return an appropriate error based on the last resolution or
// connection attempt instead. The behavior is the same for any non-gRPC
// status error.
ErrTransientFailure = errors.New("all SubConns are in TransientFailure")
)
// PickResult contains information related to a connection chosen for an RPC.
type PickResult struct {
// SubConn is the connection to use for this pick, if its state is Ready.
// If the state is not Ready, gRPC will block the RPC until a new Picker is
// provided by the balancer (using ClientConn.UpdateState). The SubConn
// must be one returned by ClientConn.NewSubConn.
SubConn SubConn
// Done is called when the RPC is completed. If the SubConn is not ready,View on GitHub (pinned to 0c51461d27)