Billionmail/BillionMail · error

resolve failed

Error message

resolve failed

What it means

ResolveA in domains/blacklist.go performs a DNS A-record lookup with retries (sleeping 1 second between attempts) and, if no *dns.A answer is obtained after all attempts, returns the sentinel error 'resolve failed'. It is a plain fmt.Errorf with no wrapped cause, so the actual DNS failure reason (timeout, NXDOMAIN, no A record) is discarded.

Source

Thrown at core/internal/service/domains/blacklist.go:355

	m.SetQuestion(dns.Fqdn(domain), dns.TypeA)

	var server string
	if len(servers) > 0 {
		server = servers[0] + ":53"
	} else {
		server = "8.8.8.8:53" // fallback
	}

	for i := 0; i < 2; i++ {
		r, _, err := c.Exchange(m, server)
		if err == nil && len(r.Answer) > 0 {
			if a, ok := r.Answer[0].(*dns.A); ok {
				return a.A.String(), nil
			}
		}
		time.Sleep(time.Second)
	}
	return "", fmt.Errorf("resolve failed")
}

// addBlacklist
func addBlacklist(domain string, blcheck_info *model.BlacklistCheckResult) {

	path := public.AbsPath("../core/data/blcheck_count.json")
	data := make(map[string]*model.BlacklistCheckResult)
	if gfile.Exists(path) {
		content := gfile.GetContents(path)
		_ = json.Unmarshal([]byte(content), &data)
	}
	data[domain] = blcheck_info
	json_data, _ := json.Marshal(data)
	_ = gfile.PutContents(path, string(json_data))
}

// ReverseIP
func ReverseIP(ip string) string {

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Verify the domain actually has an A record: dig A <domain> using the same resolver the server uses
  2. Check resolver configuration (/etc/resolv.conf) and that outbound port 53 is open
  3. Add the underlying dns error to the returned error instead of the bare sentinel for diagnosability
  4. Increase retries or use net.Resolver with context and timeouts instead of fixed 1-second sleeps

Example fix

// before
return "", fmt.Errorf("resolve failed")
// after
return "", fmt.Errorf("resolve failed for %s after %d attempts: last err %v", domain, retries, lastErr)
Defensive patterns

Strategy: retry

Validate before calling

// pre-check resolvability before blacklist scanning
ips, err := net.LookupIP(domain)
if err != nil || len(ips) == 0 {
	return fmt.Errorf("domain %s not resolvable, skip blacklist check", domain)
}

Try / catch

ip, err := ResolveA(domain)
if err != nil {
	if err.Error() == "resolve failed" {
		// treat as transient/unresolvable: log and continue with other domains
		continue
	}
	return err
}

Prevention

When it happens

Trigger: CheckBlacklist, CheckDomainsBlacklist, or IsDomainBlacklist calls ResolveA for an IP/host whose DNS query repeatedly returns no A record answer (r.Answer empty, or first answer not *dns.A) until the retry loop is exhausted.

Common situations: Querying a hostname that only has AAAA records; DNS server down or unreachable from the container/host; querying an IP literal in contexts expecting a name; corporate firewalls blocking UDP/TCP 53; transient resolver failures during blacklist scans of many domains.

Related errors


AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05). Data as JSON: /api/errors/7abca0bebdf01798. Report an issue: GitHub.