usememos/memos · warning

hostname resolved to no addresses

Error message

hostname resolved to no addresses

What it means

After DNS resolution succeeds but every returned entry either has a nil IP or was filtered out, the resolver path in internal/httpgetter returns this error. In practice it means the hostname exists in DNS but yielded no usable addresses, or all addresses were rejected as internal.

Solutions

  1. Verify the host actually resolves publicly: `dig +short <hostname>` should return at least one non-private IP
  2. If the service is internal-only, do not pass it to the metadata fetcher; the SSRF guard will never allow it
  3. Fix the DNS zone if it returns empty answers for a supposed-to-be-public name
Defensive patterns

Strategy: validation

Validate before calling

// Verify host resolves to at least one public IP before fetching
func resolvesPublicly(host string) (bool, error) {
  addrs, err := net.LookupIP(host)
  if err != nil { return false, err }
  n := 0
  for _, ip := range addrs {
    if !ip.IsLoopback() && !ip.IsPrivate() && !ip.IsLinkLocalUnicast() && !ip.IsUnspecified() { n++ }
  }
  return n > 0, nil
}

Try / catch

// Degrade to no-preview on resolution anomalies
if _, err := getter.GetHTMLMeta(u); err != nil {
  if strings.Contains(err.Error(), "no addresses") { return nil /* skip preview */ }
  return err
}

Prevention

When it happens

Trigger: A DNS response containing only CNAME-less/nil-IP records, a hostname resolving exclusively to private IPs that get stripped after the internal-IP check path, or a transient DNS misconfiguration returning empty answers.

Common situations: Internal hostnames (only private A records) passed to the link preview fetcher; broken split-horizon DNS where the public zone returns no A records; records that exist (NXDOMAIN is not returned) but carry no address data.

Related errors


AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15). Data as JSON: /api/errors/0d235722f1011ff4. Report an issue: GitHub.

Appendix: source

Thrown at internal/httpgetter/html_meta.go:98

	addrs, err := lookupIPAddr(ctx, host)
	if err != nil {
		return nil, errors.Errorf("failed to resolve hostname: %v", err)
	}

	ips := make([]net.IP, 0, len(addrs))
	for _, addr := range addrs {
		ip := addr.IP
		if ip == nil {
			continue
		}
		if isInternalIP(ip) {
			return nil, errors.Wrapf(ErrInternalIP, "host=%s, ip=%s", host, ip.String())
		}
		ips = append(ips, ip)
	}
	if len(ips) == 0 {
		return nil, errors.New("hostname resolved to no addresses")
	}

	return ips, nil
}

func isInternalIP(ip net.IP) bool {
	return ip.IsLoopback() || ip.IsPrivate() || ip.IsLinkLocalUnicast() || ip.IsUnspecified()
}

func validateURL(urlStr string) error {
	u, err := url.Parse(urlStr)
	if err != nil {
		return errors.New("invalid URL format")
	}

	if u.Scheme != "http" && u.Scheme != "https" {
		return errors.New("only http/https protocols are allowed")
	}

View on GitHub (pinned to 14d757ce1f)