{"record":{"id":"1f6f205ff46c61fe","repo":"d2lang/d2","slug":"v","errorCode":null,"errorMessage":"%v","messagePattern":"%v","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/imgbundler/imgbundler.go","lineNumber":152,"sourceCode":"\t\t\t\t\tto:   bundledImage,\n\t\t\t\t}:\n\t\t\t\t}\n\t\t\t}()\n\t\t}\n\t}()\n\n\tt := time.NewTicker(time.Second * 5)\n\tdefer t.Stop()\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn svg, fmt.Errorf(\"failed to wait for workers: %w\", ctx.Err())\n\t\tcase <-t.C:\n\t\t\tl.Info(\"fetching images...\")\n\t\tcase repl, ok := <-replc:\n\t\t\tif !ok {\n\t\t\t\tif len(errhrefs) > 0 {\n\t\t\t\t\treturn svg, fmt.Errorf(\"%v\", errhrefs)\n\t\t\t\t}\n\t\t\t\treturn svg, nil\n\t\t\t}\n\t\t\tsvg = bytes.Replace(svg, repl.from, repl.to, -1)\n\t\t}\n\t}\n}\n\nfunc worker(ctx context.Context, l simplelog.Logger, inputPath string, href []byte, isRemote, cacheImages bool) ([]byte, error) {\n\tif cacheImages {\n\t\tif hit, ok := imgCache.Load(string(href)); ok {\n\t\t\treturn hit.([]byte), nil\n\t\t}\n\t}\n\tvar buf []byte\n\tvar mimeType string\n\tvar err error\n\tif isRemote {","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/d2lang/d2/blob/0d69dca6f532ceaeacd615d35d1eaa41a238ffdb/lib/imgbundler/imgbundler.go#L134-L170","documentation":"When the worker reply channel closes, runWorkers checks errhrefs for image URLs that failed to fetch. If any failed, it returns them joined as a single error via fmt.Errorf(\"%v\", errhrefs); the caller cannot use errors.Is/As on it because it's a stringified list, not a wrapped error.","triggerScenarios":"One or more remote image hrefs in the SVG failed to download (HTTP error, DNS failure, unsupported scheme), workers finish, channel closes, and errhrefs is non-empty.","commonSituations":"Diagrams referencing private/expired image URLs, hotlinks blocked by CDNs, offline environments, or URLs requiring auth/cookies.","solutions":["Fix or remove the failing image URLs listed in the error output","Host images locally or inline them as data: URIs","Verify network access to those hosts (proxy config, firewall)","Download and reference the images via local paths to avoid remote fetch entirely"],"exampleFix":"// before (in diagram)\nicon: https://internal-wiki.company/logo.svg  // 404\n// after\nicon: https://cdn.company.com/public/logo.svg // reachable, or data:image/svg+xml;base64,...","handlingStrategy":"try-catch","validationCode":"urls := extractImageHrefs(svg)\nfor _, u := range urls {\n    resp, err := http.Head(u)\n    if err != nil || resp.StatusCode >= 400 {\n        return fmt.Errorf(\"image %s not fetchable (status %v)\", u, statusCodeOr(err))\n    }\n}","typeGuard":null,"tryCatchPattern":"svg, err := imgbundler.Bundle(ctx, svgBytes)\nif err != nil {\n    // err is a stringified list of failed hrefs — parse it for reporting\n    if strings.Contains(err.Error(), \"http\") {\n        log.Printf(\"some images failed; consider inlining them: %v\", err)\n    }\n    return err\n}","preventionTips":["Pre-validate every image URL with a HEAD request before bundling","Prefer local paths or data: URIs over remote hotlinks","Avoid URLs behind auth, expiring tokens, or bot-blocked CDNs","Treat this error's text as a URL list: split and report each failing href"],"tags":["network","imgbundler","remote-fetch"],"backgroundTag":"remote-image-fetch-failed","analyzedSha":"0d69dca6f532ceaeacd615d35d1eaa41a238ffdb","analyzedAt":"2026-08-31T12:19:21.182Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}