chenhg5/cc-connect · warning
remote image host resolved to no usable IPs
Error message
remote image host resolved to no usable IPs
What it means
This error comes from the Feishu rich-card image fetcher's custom DNS-aware dialer. After resolving the image host, every returned IP is screened by isBlockedRichCardImageIP (private, loopback, link-local, or otherwise disallowed ranges). If all resolved IPs are blocked and none was previously flagged as blocked-and-skipped, the dialer returns this error, refusing to connect as SSRF protection.
Source
Thrown at platform/feishu/feishu.go:6675
ips = append(ips, addr.IP)
}
}
var firstBlocked net.IP
for _, ip := range ips {
if isBlockedRichCardImageIP(ip) {
if firstBlocked == nil {
firstBlocked = ip
}
continue
}
dialer := &net.Dialer{Timeout: richCardImageFinalWait}
return dialer.DialContext(ctx, network, net.JoinHostPort(ip.String(), port))
}
if firstBlocked != nil {
return nil, fmt.Errorf("remote image host resolved to blocked IP %s", firstBlocked.String())
}
return nil, errors.New("remote image host resolved to no usable IPs")
}
func isBlockedRichCardImageIP(ip net.IP) bool {
addr, err := netip.ParseAddr(ip.String())
if err != nil {
return true
}
addr = addr.Unmap()
return !addr.IsGlobalUnicast() ||
addr.IsLoopback() ||
addr.IsPrivate() ||
addr.IsLinkLocalUnicast() ||
addr.IsLinkLocalMulticast() ||
addr.IsMulticast() ||
addr.IsUnspecified() ||
richCardImageIPInBlockedPrefix(addr)
}
View on GitHub (pinned to 4000b2338a)
Solutions
- Use a public image URL whose hostname resolves to public IP addresses.
- Check DNS: run `dig <host>` / `nslookup <host>` and confirm it returns publicly routable IPs, then fix records or use a CDN.
- If testing locally, expose the image via a public tunnel/host instead of localhost or an internal name.
- Verify your resolver (resolv.conf, corporate DNS, VPN split-DNS) is not mapping public hosts to internal addresses.
Example fix
// before imageURL := "http://intranet.local:8080/avatar.png" // resolves to 192.168.1.10 // after imageURL := "https://static.example.com/avatar.png" // resolves to public IPs
Defensive patterns
Strategy: validation
Validate before calling
ips, err := net.LookupIP(host)
if err != nil || len(ips) == 0 {
return fmt.Errorf("host %s does not resolve", host)
}
for _, ip := range ips {
if isPrivateOrReserved(ip) {
return fmt.Errorf("host %s resolves to non-public IP %s; image fetch will be blocked", host, ip)
}
} Try / catch
img, err := fetchRichCardImage(ctx, imageURL)
var dnsErr *net.DNSError
if errors.As(err, &dnsErr) || strings.Contains(err.Error(), "no usable IPs") {
log.Warn("image host unusable; using placeholder", "url", imageURL)
img = placeholderImage
} Prevention
- Resolve the hostname with dig/nslookup before configuring the URL and confirm public IPs
- Avoid hostnames that resolve only to RFC1918/loopback/link-local ranges
- Use a public CDN for images rather than intranet servers
- Watch for VPN/split-DNS setups that remap public hosts to internal addresses
When it happens
Trigger: Raised when net.DefaultResolver returns only IP addresses that fail isBlockedRichCardImageIP (loopback 127.0.0.0/8, RFC1918 private ranges, link-local, unspecified, etc.) for the image host, or when resolution yields no usable addresses at all (empty result without a specific blocked IP to report).
Common situations: Pointing card image URLs at internal hostnames (localhost, intranet DNS names) that resolve only to private IPs; DNS misconfiguration returning bogus addresses; environments where DNS returns only IPv6 link-local or 0.0.0.0; SSRF probe attempts.
Related errors
- redirected to unsupported image URL
- too many redirects
- remote returned non-zero code
- decode response: %w
- init failed: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/1f34a7adc0b43b6b.
Report an issue: GitHub.