Billionmail/BillionMail · error

ffmpeg compositing failed: %w\noutput: %s

Error message

ffmpeg compositing failed: %w\noutput: %s

What it means

CompositeVideo runs `ffmpeg` with the built arguments and captures combined stdout/stderr. If ffmpeg exits non-zero, the error is wrapped as 'ffmpeg compositing failed' plus ffmpeg's full output, which contains the actual diagnostic. It is the generic pass-through for any ffmpeg execution failure.

Source

Thrown at core/internal/service/video_gen/composite.go:196

}

// CompositeVideo runs FFmpeg to combine screenshots + audio into a final video.
// Requires: ffmpeg installed and in PATH.
func CompositeVideo(ctx context.Context, cfg CompositeConfig) (*CompositeResult, error) {
	args := BuildFFmpegArgs(cfg)
	if args == nil {
		return nil, fmt.Errorf("no scenes provided")
	}

	// Ensure output directory exists
	if err := os.MkdirAll(filepath.Dir(cfg.OutputPath), 0755); err != nil {
		return nil, fmt.Errorf("create output dir: %w", err)
	}

	cmd := exec.CommandContext(ctx, "ffmpeg", args...)
	out, err := cmd.CombinedOutput()
	if err != nil {
		return nil, fmt.Errorf("ffmpeg compositing failed: %w\noutput: %s", err, string(out))
	}

	// Calculate total duration from scenes
	var totalDuration time.Duration
	for _, scene := range cfg.Scenes {
		totalDuration += scene.Duration
	}

	return &CompositeResult{
		VideoPath: cfg.OutputPath,
		Duration:  totalDuration,
	}, nil
}

// SceneFromScreenshot creates a Scene from a screenshot path and audio path.
func SceneFromScreenshot(imagePath, audioPath string, duration time.Duration) Scene {
	return Scene{
		ImagePath: imagePath,

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Read the `output:` section of the error — ffmpeg prints the precise failing option/input there
  2. Ensure ffmpeg is installed and on PATH in the runtime environment
  3. Verify every scene's screenshot and audio file exists and matches the args (paths, durations)
  4. Run the exact failing ffmpeg command manually to reproduce and iterate on args
  5. If 'signal: killed'/context error, increase the timeout or reduce encode resolution/settings

Example fix

// before (Dockerfile)
RUN apt-get update && apt-get install -y imagemagick
// after
RUN apt-get update && apt-get install -y imagemagick ffmpeg
Defensive patterns

Strategy: try-catch

Validate before calling

if _, err := exec.LookPath("ffmpeg"); err != nil {
    return fmt.Errorf("ffmpeg required but not on PATH: %w", err)
}
for _, s := range cfg.Scenes {
    if _, err := os.Stat(s.ImagePath); err != nil { return err }
    if _, err := os.Stat(s.AudioPath); err != nil { return err }
}

Try / catch

res, err := video_gen.CompositeVideo(ctx, cfg)
if err != nil {
    var ee *exec.ExitError
    if errors.As(err, &ee) {
        // err's text includes ffmpeg's combined output — surface it for debugging
        log.Printf("ffmpeg exit %d. output: %s", ee.ExitCode(), extractOutput(err))
    }
    return err
}

Prevention

When it happens

Trigger: exec.CommandContext(ctx, "ffmpeg", args...).CombinedOutput() returns err — ffmpeg not installed/on PATH, invalid codec or filter args, missing input files, unsupported pixel format, context cancelled mid-encode, or out-of-memory/disk-full during encode.

Common situations: ffmpeg missing from the container image; wrong audio/video codec names in BuildFFmpegArgs; scene image paths that don't exist; context timeout shorter than the encode; ffmpeg version differences (codec name changed) between dev and prod.

Related errors


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