grpc/grpc-go · error

weighted-target: no targets to pick from

Error message

weighted-target: no targets to pick from

What it means

Thrown by StringMatcherFromProto in its default switch case when the StringMatcher proto's MatchPattern oneof is set to a variant that the library does not recognize. As of the current code, the handled variants are Exact, Prefix, Suffix, SafeRegex, and Contains. Any other oneof variant (or a nil match pattern with a new proto field) falls through to this error.

Solutions

  1. Upgrade grpc-go (and its bundled go-control-plane dependency) to a version whose StringMatcherFromProto handles the variant the control plane sends.
  2. Downgrade or patch the control plane to only use supported StringMatcher variants: exact, prefix, suffix, safe_regex, or contains.
  3. File an issue / contribute a case to StringMatcherFromProto for the new variant if it is part of the upstream proto spec.

Example fix

// before: control plane sends a new matcher variant not yet supported
string_matcher:
  some_new_match_type: "value"

// after: use a supported variant
string_matcher:
  exact: "value"
Defensive patterns

Strategy: validation

Validate before calling

// Check that the StringMatcher uses a known variant before constructing:
func validateStringMatcherProto(sm *v3matcherpb.StringMatcher) error {
    switch sm.GetMatchPattern().(type) {
    case *v3matcherpb.StringMatcher_Exact,
        *v3matcherpb.StringMatcher_Prefix,
        *v3matcherpb.StringMatcher_Suffix,
        *v3matcherpb.StringMatcher_SafeRegex,
        *v3matcherpb.StringMatcher_Contains:
        return nil
    default:
        return fmt.Errorf("unsupported StringMatcher variant: %T", sm.GetMatchPattern())
    }
}

Type guard

func isSupportedStringMatcher(sm *v3matcherpb.StringMatcher) bool {
    switch sm.GetMatchPattern().(type) {
    case *v3matcherpb.StringMatcher_Exact,
        *v3matcherpb.StringMatcher_Prefix,
        *v3matcherpb.StringMatcher_Suffix,
        *v3matcherpb.StringMatcher_SafeRegex,
        *v3matcherpb.StringMatcher_Contains:
        return true
    }
    return false
}

Prevention

When it happens

Trigger: A future or custom go-control-plane version adds a new StringMatcher variant (e.g., a hypothetical 'glob' type) and the control plane sends it, but grpc-go's StringMatcherFromProto was compiled against an older proto that does not have a case for it. The switch falls through to default.

Common situations: Version skew: the control plane uses a newer envoy.type.matcher.v3.StringMatcher proto with additional match pattern variants. A custom or patched go-control-plane that adds non-standard oneof fields. A proto deserialization quirk where GetMatchPattern() returns a type the switch does not enumerate.

Related errors


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

Appendix: source

Thrown at balancer/weightedtarget/weightedaggregator/aggregator.go:259

		// need to call it when they are resumed.
		wbsa.needUpdateStateOnResume = true
		return
	}

	wbsa.cc.UpdateState(wbsa.build())
}

// build combines sub-states into one.
//
// Caller must hold wbsa.mu.
func (wbsa *Aggregator) build() balancer.State {
	wbsa.logger.Infof("Child pickers with config: %+v", wbsa.idToPickerState)

	if len(wbsa.idToPickerState) == 0 {
		// This is the case when all sub-balancers are removed.
		return balancer.State{
			ConnectivityState: connectivity.TransientFailure,
			Picker:            base.NewErrPicker(errors.New("weighted-target: no targets to pick from")),
		}
	}

	// Make sure picker's return error is consistent with the aggregatedState.
	pickers := make([]weightedPickerState, 0, len(wbsa.idToPickerState))

	switch aggState := wbsa.csEvltr.CurrentState(); aggState {
	case connectivity.Connecting:
		return balancer.State{
			ConnectivityState: aggState,
			Picker:            base.NewErrPicker(balancer.ErrNoSubConnAvailable)}
	case connectivity.TransientFailure:
		// this means that all sub-balancers are now in TransientFailure.
		for _, ps := range wbsa.idToPickerState {
			pickers = append(pickers, *ps)
		}
		return balancer.State{
			ConnectivityState: aggState,

View on GitHub (pinned to 0c51461d27)