XTLS/Xray-core · error
failed to build IPv6 set
Error message
failed to build IPv6 set
What it means
Thrown when the go4org/netiproute IP-set builder fails to materialize the accumulated IPv6 CIDR list into an immutable IPSet during geodata IP matcher construction. The IPv4 build has already succeeded at this point, so the failure is specific to IPv6 prefix data. It is always wrapped around a Base(err) from the underlying builder (e.g. malformed IPv6 prefix, out-of-memory while inserting many prefixes).
Source
Thrown at common/geodata/ip_matcher.go:918
} else if addr.Is6() {
ipv6Builder.AddPrefix(prefix)
}
})
if err != nil {
return nil, err
}
// peak mem
runtime.GC()
defer runtime.GC()
ipv4, err := ipv4Builder.IPSet()
if err != nil {
return nil, errors.New("failed to build IPv4 set").Base(err)
}
ipv6, err := ipv6Builder.IPSet()
if err != nil {
return nil, errors.New("failed to build IPv6 set").Base(err)
}
var has4, has6 bool
var max4, max6 int
for _, p := range ipv4.Prefixes() {
has4 = true
if b := p.Bits(); b > max4 {
max4 = b
}
}
for _, p := range ipv6.Prefixes() {
has6 = true
if b := p.Bits(); b > max6 {
max6 = b
}
}
View on GitHub (pinned to 7d214f8b09)
Solutions
- Inspect the wrapped base error to see which IPv6 prefix failed; remove or fix that entry in the rule list.
- Regenerate/re-download geoip.dat (and any ext: files) from the official LXGI/runetfreedom style sources to rule out corruption.
- If loading 'geoip:cn'-style large sets in a low-memory environment, raise container memory or split rules.
- Verify each custom IPv6 CIDR with netip.ParsePrefix before adding it to config.
Example fix
// before "ip": ["2001:db8::/33-bad"] // typo'd / impossible prefix // after "ip": ["2001:db8::/33"]
Defensive patterns
Strategy: validation
Validate before calling
for _, c := range ipRules {
if strings.Contains(c, ":") && !strings.HasPrefix(c, "geoip:") && !strings.HasPrefix(c, "ext:") {
continue
}
for _, part := range strings.FieldsFunc(c, func(r rune) bool { return r == '/' }) {
if strings.Contains(part, ":") {
if _, err := netip.ParsePrefix(part); err != nil { return fmt.Errorf("bad IPv6 rule %q: %w", c, err) }
}
}
} Try / catch
if ipset, err := matcherHolder.GetIPMatcher(); err != nil {
log.Warn("geodata ipset build failed, falling back to linear matcher: ", err)
ipset = buildLinearFallback() // or abort config load
} Prevention
- Validate all custom IPv6 CIDRs with netip.ParsePrefix before config load.
- Keep geoip dat files from a single trusted source and regenerate on upgrade.
- Smoke-test full rule sets in a low-memory staging replica before deploy.
When it happens
Trigger: Calling the geodata IP matcher builder (e.g. via GetOrCreateFromGeoIPRules / newHeuristicIPMatcher) where the GeoIP dat file or custom CIDR list contains an IPv6 entry the ipset builder rejects; extremely large rule sets exhausting memory during IPSet() finalization.
Common situations: Corrupted or non-standard geosite/geolocation dat files (e.g. a Country.mmdb mistakenly used as .dat); hand-written route rules with IPv6 CIDRs of wrong byte length; upgrading Xray with an old dat file format; memory-constrained containers loading the full IPv6 delegation file.
Related errors
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/ab4c788e7104c882.
Report an issue: GitHub.