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
- 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).
- If the field may legitimately be unset in your context, check for nil before calling and skip the matcher.
- 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
- Always initialize StringMatcher protos with a concrete match pattern before sending/using them.
- Guard call sites that pull a oneof field (e.g. GetStringMatch) with a type assertion to avoid nil.
- Add a nil check in your config-decoding layer for any optional matcher field.
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
- empty contains is not allowed in StringMatcher
- empty prefix is not allowed in StringMatcher
- empty suffix is not allowed in StringMatcher
- unknown header matcher type
- gcpauthn: cache_config.cache_size must be greater than zero
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)