d2lang/d2 · error
failed to decode %q response for %s: %w
Error message
failed to decode %q response for %s: %w
What it means
httpGet reads the response body and, if the server declared a Content-Encoding, decodes it (gzip, br, deflate). If decodeContentEncoding fails, this error wraps the underlying decode failure, naming the encoding and the URL. It means the body bytes do not match the advertised Content-Encoding header.
Source
Thrown at lib/imgbundler/imgbundler.go:245
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
}
func decodeContentEncoding(buf []byte, contentEncoding string) ([]byte, error) {
encodings := strings.Split(contentEncoding, ",")
for i := len(encodings) - 1; i >= 0; i-- {
encoding := strings.TrimSpace(strings.ToLower(encodings[i]))
if encoding == "" || encoding == "identity" {
continue
}
var err error
switch encoding {
case "gzip", "x-gzip":View on GitHub (pinned to 0d69dca6f5)
Solutions
- Inspect the raw response with curl --compressed to see whether the body actually matches the declared Content-Encoding
- Fix or bypass the misbehaving proxy/CDN layer that rewrites the body
- Retry the request — a truncated transfer often resolves on re-fetch
- If you control the origin, correct the Content-Encoding header or disable compression for the asset
Defensive patterns
Strategy: try-catch
Validate before calling
// Probe that the body decodes as advertised
resp, _ := http.Get(u)
enc := resp.Header.Get("Content-Encoding")
body, _ := io.ReadAll(resp.Body)
var probe interface{ Read([]byte) (int, error) }
switch enc {
case "", "identity":
probe = bytes.NewReader(body)
case "gzip":
probe, _ = gzip.NewReader(bytes.NewReader(body))
default:
return fmt.Errorf("unsupported probe encoding %q", enc)
} Try / catch
if _, _, err := httpGet(ctx, client, href); err != nil {
var decodeErr = "failed to decode"
if strings.Contains(err.Error(), decodeErr) {
// retry without compression or log and skip this asset
}
} Prevention
- Test fetch paths through any corporate proxy with curl --compressed
- Keep Accept-Encoding limited to encodings you can decode
- Watch for middleboxes/AV that rewrite compressed responses
- Retry once without compression when decode fails
When it happens
Trigger: Server sends Content-Encoding: gzip/br/deflate but the body is not valid data in that encoding — e.g. a proxy double-encoded or stripped the encoding, a broken/buggy origin, an antivirus middlebox rewriting bodies, or truncated compressed bodies.
Common situations: Corporate proxies and TLS-terminating LBs mangling compression, CDNs serving pre-compressed assets with wrong headers, or misconfigured web servers setting the header but sending identity content.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- unsupported content encoding %q
- failed to decompress: %w
- expected status 200 but got %d %s
- Failed to decompress SourceCodePro-Italic: %v
- Failed to decompress FuzzyBubbles-Regular: %v
AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31).
Data as JSON: /api/errors/159a8d592645d8cc.
Report an issue: GitHub.