XTLS/Xray-core · error

failed to create expected ip matcher

Error message

failed to create expected ip matcher

What it means

On a range-based turn, readPaddingTurn requires the peer's total turn length to fall within [turn.minLength, turn.maxLength] (paddingTurnAcceptsLength). The received length is outside that window, meaning the two endpoints' length bounds for this turn disagree.

Source

Thrown at app/dns/nameserver.go:116

	updateRules func(bool),
) (*Client, error) {
	client := &Client{}
	err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error {
		// Create a new server for each client for now
		server, err := NewServer(ctx, ns.Address.AsDestination(), dispatcher, disableCache, serveStale, serveExpiredTTL, clientIP)
		if err != nil {
			return errors.New("failed to create nameserver").Base(err).AtWarning()
		}

		_, isLocalDNS := server.(*LocalNameServer)
		updateRules(isLocalDNS)

		// Establish expected IPs
		var expectedMatcher geodata.IPMatcher
		if len(ns.ExpectedIp) > 0 {
			expectedMatcher, err = geodata.IPReg.BuildIPMatcher(ns.ExpectedIp)
			if err != nil {
				return errors.New("failed to create expected ip matcher").Base(err).AtWarning()
			}
		}

		// Establish unexpected IPs
		var unexpectedMatcher geodata.IPMatcher
		if len(ns.UnexpectedIp) > 0 {
			unexpectedMatcher, err = geodata.IPReg.BuildIPMatcher(ns.UnexpectedIp)
			if err != nil {
				return errors.New("failed to create unexpected ip matcher").Base(err).AtWarning()
			}
		}

		if len(clientIP) > 0 {
			switch ns.Address.Address.GetAddress().(type) {
			case *net.IPOrDomain_Domain:
				errors.LogInfo(ctx, "DNS: client ", ns.Address.Address.GetDomain(), " uses clientIP ", clientIP.String())
			case *net.IPOrDomain_Ip:
				errors.LogInfo(ctx, "DNS: client ", net.IP(ns.Address.Address.GetIp()), " uses clientIP ", clientIP.String())

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Set identical minLength/maxLength for each turn on both peers
  2. Ensure any sendMinLength/sendMaxLength on the sender is within the receiver's accept window for that turn
  3. Roll out schedule changes atomically to both endpoints

Example fix

// before: sender sends 100-2000, receiver accepts 100-1000
// receiver turn: {minLength: 100, maxLength: 1000}
// after
// receiver turn: {minLength: 100, maxLength: 2000}
Defensive patterns

Strategy: validation

Validate before calling

func rangesOverlap(sender, receiver paddingTurn) bool {
    lo, hi := sender.minLength, sender.maxLength
    if sender.sendMinLength != 0 || sender.sendMaxLength != 0 {
        lo, hi = sender.sendMinLength, sender.sendMaxLength
    }
    return lo >= receiver.minLength && hi <= receiver.maxLength
}

Try / catch

if err != nil && strings.Contains(err.Error(), "is outside") {
    // bounds skew: align minLength/maxLength on both peers, then reconnect
}

Prevention

When it happens

Trigger: Sender's minLength/maxLength (or its send range draw) yields a length the receiver's [minLength, maxLength] does not cover; asymmetric configs where one side widened or narrowed the range; note the receiver checks its own bounds, not the sender's send range.

Common situations: Tuning padding bounds on the server but not clients; sending with a send range wider than the receiver's accept range (send range validation only checks it fits the sender's own bounds); version skew after config rollout.

Related errors


AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15). Data as JSON: /api/errors/a6beb92a746ae444. Report an issue: GitHub.