chenhg5/cc-connect · warning
redirected to unsupported image URL
Error message
redirected to unsupported image URL
What it means
This error is thrown by the Feishu platform's CheckRedirect hook on the HTTP client used to fetch remote images for rich cards. When the image URL redirects, every hop must still pass the isRemoteRichCardImageURL validation (http/https scheme, public host). If a redirect lands on a non-conforming URL — typically a private/internal IP, or a non-http(s) scheme — the client aborts with this error to block SSRF-style redirects.
Source
Thrown at platform/feishu/feishu.go:6599
func fetchRichCardRemoteImage(ctx context.Context, rawURL string) ([]byte, string, error) {
u, err := url.Parse(rawURL)
if err != nil || (u.Scheme != "http" && u.Scheme != "https") || u.Host == "" {
return nil, "", errors.New("invalid remote image URL")
}
client := &http.Client{
Timeout: richCardImageFinalWait,
Transport: &http.Transport{
DialContext: dialPublicRichCardImageContext,
ResponseHeaderTimeout: richCardImageFinalWait,
},
CheckRedirect: func(req *http.Request, via []*http.Request) error {
if len(via) >= 3 {
return errors.New("too many redirects")
}
if !isRemoteRichCardImageURL(req.URL.String()) {
return errors.New("redirected to unsupported image URL")
}
return nil
},
}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, rawURL, nil)
if err != nil {
return nil, "", err
}
req.Header.Set("User-Agent", "cc-connect-feishu-rich-card-image-resolver/1.0")
resp, err := client.Do(req)
if err != nil {
return nil, "", err
}
defer func() {
if err := resp.Body.Close(); err != nil {
slog.Debug("feishu: close rich card image response body", "error", err)View on GitHub (pinned to 4000b2338a)
Solutions
- Point the card image URL directly at a final, publicly reachable http(s) image URL instead of a redirector.
- If the redirect target is legitimate, host the image on an approved public host that isRemoteRichCardImageURL accepts.
- If this is your own server, fix the redirect so it lands on a public https URL, and keep the redirect chain to fewer than 3 hops.
- Download the image yourself, verify it, and serve it from a trusted static host.
Example fix
// before imageURL := "http://internal.corp/logo" // redirects to http://10.0.0.5/img // after imageURL := "https://cdn.example.com/img/logo.png" // direct public https image
Defensive patterns
Strategy: validation
Validate before calling
u, err := url.Parse(imageURL)
if err != nil || (u.Scheme != "http" && u.Scheme != "https") || !isPublicHost(u.Hostname()) {
return fmt.Errorf("image URL will fail fetch validation: %s", imageURL)
} Try / catch
img, err := fetchRichCardImage(ctx, imageURL)
if err != nil {
log.Warn("card image fetch failed; falling back to placeholder", "err", err)
img = placeholderImage
} Prevention
- Use final, direct public https image URLs, not redirectors
- Never point card images at internal/localhost hosts
- Keep redirect chains under 3 hops
- Pre-host images on your own CDN instead of third-party redirect services
When it happens
Trigger: Occurs during rich-card image download when the remote server responds with a 3xx redirect whose Location points to a URL that fails isRemoteRichCardImageURL (e.g. redirects to a private IP like 127.0.0.1/10.x.x.x, or to file:// or another scheme), or after more than 3 hops (which yields 'too many redirects' instead).
Common situations: Configuring a card image URL pointing at an internal service or local dev server that redirects; image CDNs that redirect to signed internal storage URLs; misconfigured reverse proxies; deliberate SSRF attempts via redirect chains.
Understand the failure class
Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.
Related errors
- remote image host resolved to no usable IPs
- 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/b2794bba5e1b5f74.
Report an issue: GitHub.