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

  1. Point the card image URL directly at a final, publicly reachable http(s) image URL instead of a redirector.
  2. If the redirect target is legitimate, host the image on an approved public host that isRemoteRichCardImageURL accepts.
  3. 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.
  4. 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

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


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/b2794bba5e1b5f74. Report an issue: GitHub.