d2lang/d2 · error
expected status 200 but got %d %s
Error message
expected status 200 but got %d %s
What it means
httpGet fetches a remote image over HTTP and expects a successful response. When the HTTP status code is anything other than 200, it aborts and returns this error carrying the actual status code and status text. The library only accepts a plain 200 — redirects are already followed by the client, but soft errors like 404/403/500 are surfaced here.
Source
Thrown at lib/imgbundler/imgbundler.go:233
req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36")
req.Header.Set("Accept", "image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8")
req.Header.Set("Accept-Language", "en-US,en;q=0.9")
req.Header.Set("Accept-Encoding", "gzip, deflate, br")
req.Header.Set("DNT", "1")
req.Header.Set("Upgrade-Insecure-Requests", "1")
req.Header.Set("Sec-Fetch-Dest", "image")
req.Header.Set("Sec-Fetch-Mode", "no-cors")
req.Header.Set("Sec-Fetch-Site", "cross-site")
resp, err := httpClient.Do(req)
if err != nil {
return nil, "", err
}
defer resp.Body.Close()
l.Debug(fmt.Sprintf("fetched %s remotely - response code %v", string(href), resp.StatusCode))
if resp.StatusCode != 200 {
return nil, "", fmt.Errorf("expected status 200 but got %d %s", resp.StatusCode, resp.Status)
}
r := http.MaxBytesReader(nil, resp.Body, maxImageSize)
buf, err := io.ReadAll(r)
if err != nil {
return nil, "", err
}
contentType := resp.Header.Get("Content-Type")
contentEncoding := resp.Header.Get("Content-Encoding")
if contentEncoding != "" {
buf, err = decodeContentEncoding(buf, contentEncoding)
if err != nil {
return nil, "", fmt.Errorf("failed to decode %q response for %s: %w", contentEncoding, href, err)
}
}
l.Debug(fmt.Sprintf("fetched content type: %s, Content length: %d bytes", contentType, len(buf)))
return buf, contentType, nil
}View on GitHub (pinned to 0d69dca6f5)
Solutions
- Open the URL in a browser/curl to confirm the actual status and fix or replace the image URL
- Set a browser-like User-Agent and any required Referer/auth headers if the origin blocks hotlinking
- Retry with backoff on 429/5xx; the cause is transient server-side limiting or failure
- If the image is gone, remove it from the page or substitute a valid hosted copy
Example fix
// before
resp, _, err := httpGet(ctx, client, href)
// after
// Check the URL first; on transient statuses retry
resp, _, err := httpGet(ctx, client, href)
if err != nil && (strings.Contains(err.Error(), "429") || strings.Contains(err.Error(), "50")) {
time.Sleep(backoff)
resp, _, err = httpGet(ctx, client, href)
} Defensive patterns
Strategy: retry
Validate before calling
resp, err := http.Head(imgURL)
if err != nil || resp.StatusCode != 200 {
return fmt.Errorf("image %s not fetchable: status %v", imgURL, resp.StatusCode)
} Try / catch
if _, _, err := httpGet(ctx, client, href); err != nil {
if strings.Contains(err.Error(), "expected status 200") {
// inspect status code inside message; retry on 429/5xx, skip URL on 404/403
}
} Prevention
- Pre-check image URLs for reachability before bundling
- Send a browser-like User-Agent/Referer to avoid hotlink blocks
- Use durable, pre-signed or CDN-hosted image URLs with valid expiry
- Apply backoff retry for 429/5xx statuses
When it happens
Trigger: The remote image URL returned a non-200 status: 404 (image moved/deleted), 403 (hotlink protection, missing auth, UA blocking), 5xx (origin/CDN error), or 429 (rate limiting). Raised in httpGet, called by worker during page image bundling.
Common situations: Bundling pages whose images point at expired CDN links, sites blocking non-browser user agents, signed URLs whose tokens expired, or origins rate-limiting the bundler after many requests.
Related errors
- failed to wait for workers: %w
- %v
- failed to decode %q response for %s: %w
- unsupported content encoding %q
- failed to install Playwright: %w
AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31).
Data as JSON: /api/errors/d7fa966a9aeb5cfe.
Report an issue: GitHub.