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), nil

View on GitHub (pinned to 0d69dca6f5)

Solutions

  1. Increase the context deadline passed to bundle
  2. Check that image URLs are reachable from the environment (proxy/firewall/DNS)
  3. Pre-download or inline images (data: URIs) so workers finish quickly
  4. 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

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.