XTLS/Xray-core · error

failed to create nameserver

Error message

failed to create nameserver

What it means

On a variants-based turn, readPaddingTurn accepts only total lengths equal to one of the configured variants (paddingTurnAcceptsLength compares against each variant's chunk sum). The peer's turn length matched none of them, so the schedules on the two sides disagree: the sender picked a variant the receiver does not know.

Source

Thrown at app/dns/nameserver.go:105

	return nil, errors.New("No available name server could be created from ", dest).AtWarning()
}

// NewClient creates a DNS client managing a name server with client IP, domain rules and expected IPs.
func NewClient(
	ctx context.Context,
	ns *NameServer,
	clientIP net.IP,
	disableCache bool, serveStale bool, serveExpiredTTL uint32,
	tag string,
	ipOption dns.IPOption,
	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)

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Copy the identical variants schedule to both peers (same chunk layouts in the same order)
  2. Version the schedule and negotiate/verify it at startup so mismatches fail loudly before traffic
  3. If variants differ intentionally per direction, ensure each side's receive turns list the variants the other side sends

Example fix

// before (client sends variant lengths 360/520; server only knows 360)
// server turn: variants [{100,260}]
// after (server lists both)
// server turn: variants [{100,260},{100,420}]
Defensive patterns

Strategy: validation

Validate before calling

// before connecting, confirm the peer's advertised variant lengths are all known locally
func acceptsAll(peerLengths []int, localTurn paddingTurn) bool {
    for _, l := range peerLengths {
        if !paddingTurnAcceptsLength(localTurn, l) {
            return false
        }
    }
    return true
}

Try / catch

if err != nil && strings.Contains(err.Error(), "not an allowed variant") {
    // schedule skew between peers: re-sync configs, then reconnect
}

Prevention

When it happens

Trigger: Client and server configured with different variant lists (added/removed/reordered variants); peer using sendVariants indices that reference variants absent on this side; only reachable when len(turn.variants) > 0.

Common situations: Deploying a new variant set to one endpoint only; typos when duplicating variant JSON between client and server configs; independent 'obfuscation profile' files drifting apart.

Related errors


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