MHSanaei/3x-ui · error
host %s has no IP addresses
Error message
host %s has no IP addresses
What it means
rejectPrivateHost reports this when DNS resolution succeeds with an error but returns an empty IP list — a rare resolver state distinct from NXDOMAIN (which errors). It means the name exists in some sense but the resolver handed back zero A/AAAA records, so the panel cannot even evaluate the SSRF blocklist for it.
Source
Thrown at internal/web/service/url_safety.go:76
if err := rejectPrivateHost(ctx, u.Hostname()); err != nil {
return "", err
}
return clean, nil
}
func rejectPrivateHost(ctx context.Context, hostname string) error {
if ip := net.ParseIP(hostname); ip != nil {
if isBlockedIP(ip) {
return fmt.Errorf("blocked private/internal address %s", ip.String())
}
return nil
}
ips, err := net.DefaultResolver.LookupIPAddr(ctx, hostname)
if err != nil {
return fmt.Errorf("cannot resolve host %s: %w", hostname, err)
}
if len(ips) == 0 {
return fmt.Errorf("host %s has no IP addresses", hostname)
}
for _, ipAddr := range ips {
if isBlockedIP(ipAddr.IP) {
return fmt.Errorf("host %s resolves to blocked private/internal address %s", hostname, ipAddr.IP.String())
}
}
return nil
}
func isBlockedIP(ip net.IP) bool {
return netsafe.IsBlockedIP(ip)
}
View on GitHub (pinned to ad32144c42)
Solutions
- Check what records the name actually has: 'dig <host> A <host> AAAA +short' — if empty, the name is wrong for this purpose; use the name that owns address records.
- If split-horizon DNS is involved, ensure the panel's resolver serves the view with A/AAAA records.
- Treat as a configuration error, not transient: an empty answer rarely self-heals; fix the name.
Example fix
// before url := "https://mailonly.example.com/health" // name has only MX/TXT records // after url := "https://www.example.com/health" // name with A/AAAA records
Defensive patterns
Strategy: validation
Validate before calling
// Ensure the configured name actually has address records before relying on it
addrs, err := net.LookupHost(hostname)
if err != nil || len(addrs) == 0 {
return fmt.Errorf("hostname %q has no A/AAAA records", hostname)
} Type guard
null
Try / catch
if strings.Contains(err.Error(), "no IP addresses") {
// permanent config error: pick a name that owns A/AAAA records
} Prevention
- When adding health-check targets, dig them for A/AAAA first.
- Avoid names that only carry MX/TXT records.
When it happens
Trigger: Hostnames with only non-address records (e.g. a name that has only an MX/TXT record and no A/AAAA), or aresolver/misconfigured DNS middleware returning empty NOERROR answers.
Common situations: Pointing a health-check at a mail-only or TXT-only name; DNS firewalls (Response Policy Zones) that strip answers; some split-horizon setups where the public view has no A record.
Related errors
- cannot resolve host %s: %w
- blocked private/internal address %s
- no usable address for %s
- stopped after 10 redirects
- blocked private/internal address %s
AI-assisted analysis of MHSanaei/3x-ui@ad32144c42 (2026-08-15).
Data as JSON: /api/errors/c31da463a4b8e59f.
Report an issue: GitHub.