Tencent/WeKnora · error

HTTP GET: %w

Error message

HTTP GET: %w

What it means

This error wraps a transport-level failure of the HTTP GET performed during remote image download — the request could not be completed at all. The underlying error (DNS, dial, TLS, timeout, context cancellation) is preserved via %w.

Source

Thrown at internal/infrastructure/docparser/image_resolver.go:1017

	images = append(images, mdImages...)
	images = append(images, htmlImages...)
	return markdown, images, nil
}

// downloadImage fetches an image from remoteURL using the provided SSRF-safe
// client. It validates Content-Type and enforces maxRemoteImageSize.
func downloadImage(ctx context.Context, client *http.Client, remoteURL string) (data []byte, mimeType string, err error) {
	req, err := http.NewRequestWithContext(ctx, http.MethodGet, remoteURL, nil)
	if err != nil {
		return nil, "", fmt.Errorf("create request: %w", err)
	}
	// Some CDNs require a browser-like User-Agent.
	req.Header.Set("User-Agent", "Mozilla/5.0 (compatible; WeKnora/1.0)")

	resp, err := client.Do(req)
	if err != nil {
		return nil, "", fmt.Errorf("HTTP GET: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, "", fmt.Errorf("unexpected status %d", resp.StatusCode)
	}

	// Determine MIME type from Content-Type header.
	ct := resp.Header.Get("Content-Type")
	mimeType, _, _ = mime.ParseMediaType(ct)
	if mimeType == "" {
		mimeType = "application/octet-stream"
	}

	// Only allow image content types (or octet-stream which we sniff later).
	if !strings.HasPrefix(mimeType, "image/") && mimeType != "application/octet-stream" {
		return nil, "", fmt.Errorf("non-image content type: %s", mimeType)
	}

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Unwrap and classify the error (net.Error timeout, DNS, TLS) before retrying
  2. Verify the image host resolves and is reachable from the server (curl the URL)
  3. Check egress rules/proxy/timeout settings on the SSRF-safe HTTP client
  4. Retry only transient errors (timeouts, connection reset) with backoff

Example fix

// before
resp, err := client.Do(req)
if err != nil { return nil, "", fmt.Errorf("HTTP GET: %w", err) }
// after
resp, err := client.Do(req)
if err != nil {
    var ne net.Error
    if errors.As(err, &ne) && ne.Timeout() {
        return nil, "", fmt.Errorf("HTTP GET (timeout): %w", err)
    }
    return nil, "", fmt.Errorf("HTTP GET: %w", err)
}
Defensive patterns

Strategy: retry

Validate before calling

// resolve host before fetching
if _, err := net.LookupHost(url.Host); err != nil {
    return fmt.Errorf("host does not resolve: %w", err)
}

Try / catch

data, mimeType, err := downloadImage(ctx, client, remoteURL)
if err != nil {
    var ne net.Error
    if errors.As(err, &ne) && ne.Timeout() {
        // retry once with longer timeout
    }
    if errors.Is(err, context.Canceled) {
        return nil, "", err // do not retry cancellation
    }
    return nil, "", fmt.Errorf("HTTP GET: %w", err)
}

Prevention

When it happens

Trigger: downloadImage's client.Do fails: DNS resolution failure, connection refused, TLS handshake error, request timeout, or the context was cancelled while fetching the image.

Common situations: Image host unreachable or DNS broken, egress firewall blocking outbound requests, slow hosts exceeding the SSRF-safe client's timeout, caller cancelled the context mid-download.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/675b24e56df10027. Report an issue: GitHub.