d2lang/d2 · error
failed to wait for workers: %w
Error message
failed to wait for workers: %w
What it means
runWorkers orchestrates remote image fetching for SVG bundling and waits on a select loop. If the context is cancelled (deadline exceeded or explicitly cancelled) before all worker replies arrive on replc, it aborts with this wrapped ctx.Err(). The bundle ultimately fails rather than emitting an SVG with missing images.
Source
Thrown at lib/imgbundler/imgbundler.go:146
return
}
select {
case <-ctx.Done():
case replc <- repl{
from: img[0],
to: bundledImage,
}:
}
}()
}
}()
t := time.NewTicker(time.Second * 5)
defer t.Stop()
for {
select {
case <-ctx.Done():
return svg, fmt.Errorf("failed to wait for workers: %w", ctx.Err())
case <-t.C:
l.Info("fetching images...")
case repl, ok := <-replc:
if !ok {
if len(errhrefs) > 0 {
return svg, fmt.Errorf("%v", errhrefs)
}
return svg, nil
}
svg = bytes.Replace(svg, repl.from, repl.to, -1)
}
}
}
func worker(ctx context.Context, l simplelog.Logger, inputPath string, href []byte, isRemote, cacheImages bool) ([]byte, error) {
if cacheImages {
if hit, ok := imgCache.Load(string(href)); ok {
return hit.([]byte), nilView on GitHub (pinned to 0d69dca6f5)
Solutions
- Increase the context deadline passed to bundle
- Check that image URLs are reachable from the environment (proxy/firewall/DNS)
- Pre-download or inline images (data: URIs) so workers finish quickly
- Add retry/backoff for flaky hosts and inspect the wrapped ctx.Err() to confirm deadline vs cancel
Example fix
// before ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) // after ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
Defensive patterns
Strategy: try-catch
Validate before calling
for _, u := range imageHrefs {
req, _ := http.NewRequestWithContext(ctx, http.MethodHead, u, nil)
if _, err := http.DefaultClient.Do(req); err != nil {
return fmt.Errorf("unreachable image %s: %w", u, err)
}
} Try / catch
svg, err := imgbundler.Bundle(ctx, svgBytes)
if err != nil {
if errors.Is(err, context.DeadlineExceeded) {
// retry with larger budget or pre-fetch images
log.Printf("bundle timed out: %v", err)
}
return err
} Prevention
- Give bundle a generous context timeout proportional to the number of images
- Pre-download remote images or inline them as data: URIs
- Verify proxy/firewall allows outbound requests in CI environments
- Use ctx.Err() via errors.Is to distinguish timeout from cancellation
When it happens
Trigger: Calling bundle with a context whose deadline expires while image downloads are still in flight, or cancelling the context mid-run; also network stalls that keep workers from finishing within the budget.
Common situations: Slow/unreachable remote image hosts behind the URLs in the diagram, short context timeouts in CI, or large diagrams referencing many remote images.
Related errors
AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31).
Data as JSON: /api/errors/add45300c8a88af9.
Report an issue: GitHub.