{"record":{"id":"0d235722f1011ff4","repo":"usememos/memos","slug":"hostname-resolved-to-no-addresses","errorCode":null,"errorMessage":"hostname resolved to no addresses","messagePattern":"hostname resolved to no addresses","errorType":"http","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/httpgetter/html_meta.go","lineNumber":98,"sourceCode":"\n\taddrs, err := lookupIPAddr(ctx, host)\n\tif err != nil {\n\t\treturn nil, errors.Errorf(\"failed to resolve hostname: %v\", err)\n\t}\n\n\tips := make([]net.IP, 0, len(addrs))\n\tfor _, addr := range addrs {\n\t\tip := addr.IP\n\t\tif ip == nil {\n\t\t\tcontinue\n\t\t}\n\t\tif isInternalIP(ip) {\n\t\t\treturn nil, errors.Wrapf(ErrInternalIP, \"host=%s, ip=%s\", host, ip.String())\n\t\t}\n\t\tips = append(ips, ip)\n\t}\n\tif len(ips) == 0 {\n\t\treturn nil, errors.New(\"hostname resolved to no addresses\")\n\t}\n\n\treturn ips, nil\n}\n\nfunc isInternalIP(ip net.IP) bool {\n\treturn ip.IsLoopback() || ip.IsPrivate() || ip.IsLinkLocalUnicast() || ip.IsUnspecified()\n}\n\nfunc validateURL(urlStr string) error {\n\tu, err := url.Parse(urlStr)\n\tif err != nil {\n\t\treturn errors.New(\"invalid URL format\")\n\t}\n\n\tif u.Scheme != \"http\" && u.Scheme != \"https\" {\n\t\treturn errors.New(\"only http/https protocols are allowed\")\n\t}","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/usememos/memos/blob/14d757ce1fb31c78590f374bc042f8dbedbc20d7/internal/httpgetter/html_meta.go#L80-L116","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify the host actually resolves publicly: `dig +short <hostname>` should return at least one non-private IP","If the service is internal-only, do not pass it to the metadata fetcher; the SSRF guard will never allow it","Fix the DNS zone if it returns empty answers for a supposed-to-be-public name"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Verify host resolves to at least one public IP before fetching\nfunc resolvesPublicly(host string) (bool, error) {\n  addrs, err := net.LookupIP(host)\n  if err != nil { return false, err }\n  n := 0\n  for _, ip := range addrs {\n    if !ip.IsLoopback() && !ip.IsPrivate() && !ip.IsLinkLocalUnicast() && !ip.IsUnspecified() { n++ }\n  }\n  return n > 0, nil\n}","typeGuard":null,"tryCatchPattern":"// Degrade to no-preview on resolution anomalies\nif _, err := getter.GetHTMLMeta(u); err != nil {\n  if strings.Contains(err.Error(), \"no addresses\") { return nil /* skip preview */ }\n  return err\n}","preventionTips":["Check DNS for user-supplied hosts in dev before enabling previews","Do not use internal-only hostnames with the fetcher","Keep preview generation optional and failure-tolerant"],"tags":["network","dns","ssrf"],"backgroundTag":null,"analyzedSha":"14d757ce1fb31c78590f374bc042f8dbedbc20d7","analyzedAt":"2026-08-15T09:27:36.538Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}