grpc/grpc-go · error
empty prefix is not allowed in StringMatcher
Error message
empty prefix is not allowed in StringMatcher
What it means
Inside StringMatcherFromProto (string_matcher.go:97), the Prefix variant of the StringMatcher oneof requires a non-empty prefix string. An empty prefix would match everything and is semantically meaningless (and ambiguous with a true catch-all), so line 107-108 rejects it.
Solutions
- Provide a non-empty prefix string in the StringMatcher config.
- If a catch-all is intended, omit the matcher entirely (or use a different mechanism) instead of using an empty prefix.
- Audit the upstream xDS/RBAC/route configuration for empty prefix values and remove or fill them.
Example fix
// before
sm, err := matcher.StringMatcherFromProto(&v3matcherpb.StringMatcher{
MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: ""},
}) // err: empty prefix is not allowed
// after
sm, err := matcher.StringMatcherFromProto(&v3matcherpb.StringMatcher{
MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: "/svc/a"},
}) Defensive patterns
Strategy: validation
Validate before calling
func validateStringMatcherProto(p *v3matcherpb.StringMatcher) error {
if p == nil { return errors.New("nil StringMatcher") }
if prefix := p.GetPrefix(); prefix == "" && fmt.Sprintf("%T", p.GetMatchPattern()) == "*matcher.StringMatcher_Prefix" {
return errors.New("StringMatcher.prefix must not be empty")
}
return nil
} Prevention
- In your control-plane config generator, never default prefix to empty — omit the matcher if unused.
- Add a policy linter that flags `prefix: ""` in RBAC/route configs.
- Use explicit `omitempty` semantics in YAML/JSON templates so empty values disappear.
When it happens
Trigger: Triggered when an xDS config provides a StringMatcher with the prefix pattern set to the empty string (`prefix: ""`). Encountered while decoding header matchers, path matchers, or any field that compiles down to a StringMatcher.
Common situations: A control-plane policy that defaulted prefix to empty instead of omitting it; YAML config written as `prefix:` with no value; an Envoy config ported to gRPC where an empty prefix was tolerated; a templating bug that produces `prefix: ""`.
Related errors
- empty contains is not allowed in StringMatcher
- empty suffix is not allowed in StringMatcher
- input StringMatcher proto is nil
- 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/b69462e32b2640e6.
Report an issue: GitHub.
Appendix: source
Thrown at internal/xds/matcher/string_matcher.go:108
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()
re, err := CompileSafeRegex(regex)
if err != nil {
return StringMatcher{}, fmt.Errorf("safe_regex matcher %q is invalid", regex)
}
matcher = NewRegexStringMatcher(re)
case *v3matcherpb.StringMatcher_Contains:
if matcherProto.GetContains() == "" {
return StringMatcher{}, errors.New("empty contains is not allowed in StringMatcher")
}View on GitHub (pinned to 0c51461d27)