Billionmail/BillionMail · error

imagemagick annotate failed: %w\noutput: %s

Error message

imagemagick annotate failed: %w\noutput: %s

What it means

Annotate shells out to ImageMagick's `magick` CLI to draw annotations onto an image. If the command exits non-zero, it wraps the exec error together with the combined stdout/stderr so the caller can see why ImageMagick failed. It is thrown for any magick invocation failure: missing binary, unreadable input, bad arguments, or ImageMagick processing errors.

Source

Thrown at core/internal/service/video_gen/annotate.go:101

				Type: AnnotationText,
				X:    100, Y: 950,
				Text:  "High ad spend but room for improvement",
				Color: "#FF6600",
			})
		}
		return anns
	}
	return nil
}

// Annotate applies visual annotations to a screenshot using ImageMagick.
// Requires: convert (ImageMagick) installed.
func Annotate(ctx context.Context, cfg AnnotateConfig) error {
	args := BuildAnnotateArgs(cfg)
	cmd := exec.CommandContext(ctx, "magick", args...)
	out, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("imagemagick annotate failed: %w\noutput: %s", err, string(out))
	}
	return nil
}

// BuildAnnotateArgs constructs the ImageMagick CLI arguments for the given config.
// Exported for testing without requiring ImageMagick installed.
func BuildAnnotateArgs(cfg AnnotateConfig) []string {
	args := []string{cfg.InputPath}

	for _, ann := range cfg.Annotations {
		color := ann.Color
		if color == "" {
			color = "red"
		}

		switch ann.Type {
		case AnnotationCircle:
			// Draw a circle outline

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Install ImageMagick 7 (which provides `magick`) and ensure it is on PATH: apt-get install imagemagick (v7) or imagemagick7
  2. Check the `output:` portion of the error for the specific magick CLI complaint
  3. Verify the input file exists and is readable, and the output directory is writable
  4. Run the BuildAnnotateArgs output manually to reproduce: magick <args...>
  5. If the error is 'signal: killed' or context deadline, increase the timeout or image size limits

Example fix

// before (CI Dockerfile)
FROM golang:1.22
// after
FROM golang:1.22
RUN apt-get update && apt-get install -y imagemagick && rm -rf /var/lib/apt/lists/*
Defensive patterns

Strategy: try-catch

Validate before calling

func magickAvailable() error {
    path, err := exec.LookPath("magick")
    if err != nil { return fmt.Errorf("ImageMagick v7 'magick' not on PATH: %w", err) }
    return nil
}
// also pre-check: file exists
if _, err := os.Stat(cfg.InputPath); err != nil { return err }

Try / catch

if err := video_gen.Annotate(ctx, cfg); err != nil {
    var ee *exec.ExitError
    if errors.As(err, &ee) {
        log.Printf("magick failed (exit %d): %s", ee.ExitCode(), err)
        return fmt.Errorf("install ImageMagick or fix args: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: exec.CommandContext(ctx, "magick", args...) returns a non-nil error — magick not installed/not on PATH, input file missing or unreadable, invalid annotate arguments, disk full, or context cancelled before completion.

Common situations: ImageMagick not installed in the container/host (video_gen requires it); typo'd image path; policy.xml restricting operations; arguments producing an option error visible in `output`; context deadline exceeded on large images.

Related errors


AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05). Data as JSON: /api/errors/7233075c5b7b32e3. Report an issue: GitHub.