XTLS/Xray-core · error · errors.Error

failed to get IP address for domain {domain}

Error message

failed to get IP address for domain {domain}

What it means

With domainStrategy UseIP/UseIPv4/UseIPv6, freedom resolves the destination domain itself before dialing. On the first resolve it queries the system resolver for A records (if IPv4 routes exist) then AAAA (if IPv6 routes exist); if both come back empty, it fails with this error naming the domain. The lookup uses Go's net.DefaultResolver, so it follows /etc/resolv.conf and the OS.

Source

Thrown at proxy/freedom/freedom.go:322

					Address: net.IPAddress(ips[dice.Roll(len(ips))]),
					Port:    dialDest.Port,
				}
				errors.LogInfo(ctx, "dialing to ", dialDest)
			}
		} else if h.shouldResolveDomainBeforeFinalRules(dialDest, defaultRule) { // asis + domain + hasrules
			domain := dialDest.Address.Domain()
			var ips []net.IP
			if firstResolve {
				firstResolve = false
				supportIPv4, supportIPv6 := utils.CheckRoutes()
				if supportIPv4 {
					ips, _ = net.DefaultResolver.LookupIP(ctx, "ip4", domain)
				}
				if len(ips) == 0 && supportIPv6 {
					ips, _ = net.DefaultResolver.LookupIP(ctx, "ip6", domain)
				}
				if len(ips) == 0 {
					return errors.New("failed to get IP address for domain ", domain)
				}
			} else {
				ips, _ = net.DefaultResolver.LookupIP(ctx, "ip", domain)
			}
			if len(ips) == 0 { // SRV/TXT, lookup failed
				return errors.New("failed to get IP address for domain ", domain)
			}
			if addr := net.IPAddress(ips[dice.Roll(len(ips))]); addr != nil {
				dialDest.Address = addr
				errors.LogInfo(ctx, "dialing to ", dialDest)
			}
		}
		if rule := h.matchFinalRule(dialDest.Network, dialDest.Address, dialDest.Port, defaultRule); rule != nil && rule.action == RuleAction_Block {
			blockedDest = &dialDest
			blockedRule = rule
			return nil
		}

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. From the Xray host, run `dig <domain> A +short` and `dig <domain> AAAA +short` to confirm the system resolver returns records
  2. Fix /etc/resolv.conf or the container's DNS settings so net.DefaultResolver works
  3. If DNS is intentionally handled elsewhere, set domainStrategy to "AsIs" so freedom dials by name
  4. Verify the host actually has IPv4/IPv6 routes (CheckRoutes gates the lookups)

Example fix

// before
"settings": { "domainStrategy": "UseIP" }
// after (let remote/proxy resolve, or fix host DNS first)
"settings": { "domainStrategy": "AsIs" }
Defensive patterns

Strategy: validation

Validate before calling

```go
if ips, err := net.DefaultResolver.LookupIP(ctx, "ip", domain); err != nil || len(ips) == 0 {
    // skip UseIP strategy or fail fast with a clear reason
}
```

Prevention

When it happens

Trigger: destination.domainStrategy set to UseIP/UseIPv4/UseIPv6 plus a domain that returns no A/AAAA records (NXDOMAIN, DNS-only-HTTPS records), or a broken system resolver on the Xray host. Also triggered when CheckRoutes() reports no usable IPv4/IPv6 route so both lookups are skipped.

Common situations: Host with no DNS configured (containers with empty resolv.conf), IPv6 disabled at the OS but strategy forcing ip6, typo'd domain, or a resolver that filters records. Because the error is swallowed into `ips, _`, the real DNS error is invisible — check with `dig @<resolver> <domain> A` on the host.

Related errors


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