grpc/grpc-go · error

input StringMatcher proto is nil

Error message

input StringMatcher proto is nil

What it means

`StringMatcherFromProto` (internal/xds/matcher/string_matcher.go:97) constructs a StringMatcher from the Envoy StringMatcher proto. The very first check at line 98-99 rejects a nil input proto. This is a defensive guard: the function cannot read a match pattern from a nil pointer, so it fails fast with a clear message rather than dereferencing.

Solutions

  1. Ensure the proto field passed to StringMatcherFromProto is populated — initialize the StringMatcher proto with one of the match patterns (exact/prefix/suffix/contains/safe_regex).
  2. If the field may legitimately be unset in your context, check for nil before calling and skip the matcher.
  3. Inspect the upstream xDS configuration (header matcher, path matcher) to find the empty `string_match` block and fill it in.

Example fix

// before
sm, err := matcher.StringMatcherFromProto(nil) // err: input StringMatcher proto is nil

// after
sm, err := matcher.StringMatcherFromProto(&v3matcherpb.StringMatcher{
    MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "foo"},
})
Defensive patterns

Strategy: type-guard

Validate before calling

func safeStringMatcherFromProto(p *v3matcherpb.StringMatcher) (matcher.StringMatcher, error) {
    if p == nil {
        return matcher.StringMatcher{}, errors.New("StringMatcher proto is required")
    }
    return matcher.StringMatcherFromProto(p)
}

Type guard

// Narrow a oneof field before passing it to StringMatcherFromProto.
func stringMatcherOrNil(hm *route_componentspb.HeaderMatcher) *v3matcherpb.StringMatcher {
    if sm, ok := hm.HeaderMatchSpecifier.(*route_componentspb.HeaderMatcher_StringMatch); ok {
        return sm.StringMatch
    }
    return nil
}

Prevention

When it happens

Trigger: Triggered when StringMatcherFromProto is called with a nil `*v3matcherpb.StringMatcher`. Call sites include header matchers, path matchers (newURLPathMatcher), and other xDS resource decoders that build matchers from proto fields which may be unset.

Common situations: An xDS configuration referencing a StringMatcher-typed field that was never populated (e.g. a header matcher with `string_match` left empty in YAML); a code path that pulls `GetStringMatch()` from a HeaderMatcher whose `HeaderMatchSpecifier` oneof is not the StringMatch variant, yielding nil; tests passing a literal nil.

Related errors


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

Appendix: source

Thrown at internal/xds/matcher/string_matcher.go:99

		return nil
	}

	s := new(string)
	if ignoreCase {
		*s = strings.ToLower(*input)
	} else {
		*s = *input
	}
	return s
}

// StringMatcherFromProto is a helper function to create a StringMatcher from
// the corresponding StringMatcher proto.
//
// Returns a non-nil error if matcherProto is invalid.
func StringMatcherFromProto(matcherProto *v3matcherpb.StringMatcher) (StringMatcher, error) {
	if matcherProto == nil {
		return StringMatcher{}, errors.New("input StringMatcher proto is nil")
	}

	matcher := StringMatcher{ignoreCase: matcherProto.GetIgnoreCase()}
	switch mt := matcherProto.GetMatchPattern().(type) {
	case *v3matcherpb.StringMatcher_Exact:
		matcher.exactMatch = newStrPtr(&mt.Exact, matcher.ignoreCase)
	case *v3matcherpb.StringMatcher_Prefix:
		if matcherProto.GetPrefix() == "" {
			return StringMatcher{}, errors.New("empty prefix is not allowed in StringMatcher")
		}
		matcher.prefixMatch = newStrPtr(&mt.Prefix, matcher.ignoreCase)
	case *v3matcherpb.StringMatcher_Suffix:
		if matcherProto.GetSuffix() == "" {
			return StringMatcher{}, errors.New("empty suffix is not allowed in StringMatcher")
		}
		matcher.suffixMatch = newStrPtr(&mt.Suffix, matcher.ignoreCase)
	case *v3matcherpb.StringMatcher_SafeRegex:
		regex := matcherProto.GetSafeRegex().GetRegex()

View on GitHub (pinned to 0c51461d27)