Billionmail/BillionMail · error

annotate %s: %w

Error message

annotate %s: %w

What it means

AnnotateAll iterates over scene types, calling Annotate for each. If any single annotation pass fails, the whole batch aborts and the error is wrapped with the scene type so you know which image failed. It is a pass-through wrapper — the root cause is always in the inner 'imagemagick annotate failed' error.

Source

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

		output string
	}{
		{ScreenshotHomepage, result.Homepage, annotated.Homepage},
		{ScreenshotContact, result.Contact, annotated.Contact},
		{ScreenshotGoogle, result.Google, annotated.Google},
	}

	for _, p := range pairs {
		anns := DefaultAnnotations(p.typ, signals)
		if len(anns) == 0 {
			// No annotations — just copy
			anns = nil
		}
		if err := Annotate(ctx, AnnotateConfig{
			InputPath:   p.input,
			OutputPath:  p.output,
			Annotations: anns,
		}); err != nil {
			return nil, fmt.Errorf("annotate %s: %w", p.typ, err)
		}
	}

	return annotated, nil
}

// annotatedPath derives the annotated output path from the original.
func annotatedPath(original string) string {
	ext := filepath.Ext(original)
	base := strings.TrimSuffix(original, ext)
	return base + "_annotated" + ext
}

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Read the wrapped cause: the scene type in this message plus the 'output:' text from the inner error
  2. Check that the input screenshot and output path for that specific scene type exist and are writable
  3. Run the failing scene's magick command manually to isolate the bad argument
  4. Ensure ImageMagick is installed in the environment running AnnotateAll
  5. Add pre-flight validation of scene configs/paths before starting the batch

Example fix

// before
if _, err := os.Stat(p.input); err != nil { /* proceeds anyway */ }
// after
if _, err := os.Stat(p.input); err != nil {
    return nil, fmt.Errorf("scene %s input missing: %w", p.typ, err)
}
Defensive patterns

Strategy: validation

Validate before calling

for _, p := range scenes {
    if _, err := os.Stat(p.input); err != nil {
        return nil, fmt.Errorf("scene %s: input missing: %w", p.typ, err)
    }
}
if err := exec.Command("magick", "-version").Run(); err != nil {
    return nil, errors.New("magick not available for annotate batch")
}

Try / catch

annotated, err := video_gen.AnnotateAll(ctx, scenes)
if err != nil {
    var sceneErr error
    if strings.HasPrefix(err.Error(), "annotate ") {
        sceneErr = errors.Unwrap(err) // inspect the magick failure for the specific scene
    }
    return fmt.Errorf("annotate batch aborted: %w (cause: %v)", err, sceneErr)
}

Prevention

When it happens

Trigger: Annotate returns an error for a scene with type p.typ — magick missing, bad input/output path for that scene, or invalid annotation config for that scene type.

Common situations: One scene's screenshot file missing while others succeed; per-scene annotation text/config invalid; ImageMagick installed for some runners but not others; running during pipeline where a prior screenshot step silently failed.

Related errors


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