XTLS/Xray-core · error
empty domain rule list
Error message
empty domain rule list
What it means
Returned by MphDomainMatcherFactory.BuildMatcher when the rules slice is empty. The minimal perfect hash (MPH) matcher used on desktop platforms requires at least one domain rule to build its strmatcher.MphValueMatcher; an empty set is treated as a caller bug or an upstream routing misconfiguration rather than 'match nothing'.
Source
Thrown at common/geodata/domain_matcher.go:63
sb.WriteString(":")
sb.WriteString(v.Geosite.Code)
sb.WriteString("@")
sb.WriteString(v.Geosite.Attrs)
sb.WriteString(",")
default:
panic("unknown domain rule type")
}
}
if !cache {
return ""
}
return sb.String()
}
// BuildMatcher implements DomainMatcherFactory.
func (f *MphDomainMatcherFactory) BuildMatcher(rules []*DomainRule) (DomainMatcher, error) {
if len(rules) == 0 {
return nil, errors.New("empty domain rule list")
}
key := buildDomainRulesKey(rules)
if key != "" {
f.Lock()
defer f.Unlock()
if g, ok := f.shared.Load(key); ok {
errors.LogDebug(context.Background(), "geodata mph domain matcher cache HIT for ", len(rules), " rules")
return g, nil
}
errors.LogDebug(context.Background(), "geodata mph domain matcher cache MISS for ", len(rules), " rules")
}
g := strmatcher.NewMphValueMatcher()
for i, r := range rules {
switch v := r.Value.(type) {
case *DomainRule_Custom:
m, err := parseDomain(v.Custom)
if err != nil {
return nil, errView on GitHub (pinned to 7d214f8b09)
Solutions
- Check len(rules) == 0 before building and skip/return a nil-matcher no-op policy for that rule.
- Fix the source of emptiness: verify the geosite code exists (geosite:cn etc.) and that rule parsing actually appended entries.
- Validate routing config so rules with empty effective domain lists are rejected at load time.
Example fix
// before
m, err := factory.BuildMatcher(rules) // rules may be empty -> error
// after
if len(rules) == 0 {
return nil // nothing to match; skip this rule
}
m, err := factory.BuildMatcher(rules) Defensive patterns
Strategy: validation
Validate before calling
if len(rules) == 0 { return nil /* skip rule */ }
m, err := factory.BuildMatcher(rules) Type guard
func hasDomainRules(rules []*geodata.DomainRule) bool { return len(rules) > 0 } Try / catch
m, err := factory.BuildMatcher(rules)
if err != nil && strings.Contains(err.Error(), "empty domain rule list") {
return nil // treat as no-op rule
} Prevention
- Check rule counts after geosite resolution, before matcher build
- Validate routing configs reject rules whose domain lists resolve empty
When it happens
Trigger: Calling BuildMatcher with a zero-length []*geodata.DomainRule — e.g. a routing rule whose geosite/geoip resolution produced no entries (mistyped geosite code that matched nothing via fallback), or programmatically building a matcher from an empty filtered rule list.
Common situations: Routing configs referencing a geosite code that does not exist in geosite.dat (loader returns nothing); custom code that filters domain rules down to zero and still tries to build a matcher; empty 'domainStrategy' rule lists after JSON merge.
Related errors
- unknown domain type:
- failed to open
- failed to check code
- failed to load code
- failed to build IPv4 set
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/dd1b284c6ee84889.
Report an issue: GitHub.