# How to Handle Video Errors with video-use: A Complete Guide to Robust FFmpeg Pipelines

> Learn to handle video errors with video-use by wrapping subprocess calls in try except blocks. Prevent pipeline crashes with user friendly messages. Master robust FFmpeg pipelines.

- Repository: [Browser Use/video-use](https://github.com/browser-use/video-use)
- Tags: how-to-guide
- Published: 2026-07-10

---

**Wrap every `subprocess.run` invocation in [`helpers/render.py`](https://github.com/browser-use/video-use/blob/main/helpers/render.py) with a `try/except` block to catch `CalledProcessError` and provide user-friendly messages instead of allowing the pipeline to crash with a Python traceback.**

When processing video with **video-use**, the pipeline relies heavily on **FFmpeg** invoked via `subprocess.run` to extract segments, detect HDR metadata, and composite final outputs. If source files are missing, codecs are unsupported, or filter graphs fail, the default behavior is an immediate crash with a `CalledProcessError`. Understanding how to handle video errors with video-use requires knowing where the pipeline is fragile and how to inject resilience into the subprocess-heavy workflow.

## Understanding the Error Handling Architecture in video-use

The codebase delegates heavy lifting to FFmpeg, creating specific failure points across the rendering pipeline defined in [`helpers/render.py`](https://github.com/browser-use/video-use/blob/main/helpers/render.py).

### Input Validation and Early Exits

The CLI entry point performs minimal validation. At lines 78-80, the script checks if the EDL file exists and calls `sys.exit` immediately if not, printing a clear "edl not found" message. However, this validation does not extend to the source media files referenced within the EDL.

### FFmpeg Subprocess Calls and Uncaught Exceptions

Most critical operations use `subprocess.run(..., check=True)`, which raises `CalledProcessError` when FFmpeg returns a non-zero exit code. The following functions lack error handling:

- **Segment extraction** (lines 161-210): Long-running FFmpeg commands for scaling, grading, and audio fades.
- **Concatenation** (lines 66-82): Uses the concat demuxer; any error bubbles up and stops execution.
- **Final compositing** (lines 506-570): Overlays and subtitles stitched together; filter graph errors cause immediate abortion.

In all these cases, the script does not catch the exception, exposing the user to a raw Python stack trace.

### Graceful Fallbacks for HDR and Portrait Detection

Not all operations crash on failure. The HDR detection logic (lines 121-132) and portrait detection (lines 134-147) wrap `ffprobe` calls in `try/except` blocks that return `False` on failure. This allows the pipeline to fall back to SDR processing or default aspect ratios without terminating, a pattern you should replicate for other optional features.

## Step-by-Step Error Handling Strategies

To make the pipeline production-ready, implement these defensive patterns derived from the source code.

### Pre-flight Source File Verification

Before invoking the render pipeline, verify that every source referenced in the EDL exists. The current code at lines 87-92 uses `resolve_path` to turn relative paths into absolute ones, but performs no existence checks on the resulting paths.

Insert this validation near the start of your `main()` function:

```python
from pathlib import Path
import sys

def verify_sources(edl: dict, edit_dir: Path) -> None:
    """Verify every source file exists before rendering starts."""
    missing = []
    for name, path_str in edl["sources"].items():
        path = resolve_path(path_str, edit_dir)
        if not path.is_file():
            missing.append(str(path))
    if missing:
        sys.exit(f"❌ Missing source files: {', '.join(missing)}")

```

### Wrapping FFmpeg Calls with Safe Runners

Replace direct `subprocess.run` calls in `extract_segment`, `concat_segments`, `build_final_composite`, and `apply_loudnorm_two_pass` with a wrapper that catches `CalledProcessError`:

```python
import subprocess

def run_ffmpeg(cmd: list[str], quiet: bool = False) -> None:
    """Execute FFmpeg with friendly error handling."""
    try:
        subprocess.run(
            cmd, 
            check=True,
            stdout=subprocess.DEVNULL,
            stderr=subprocess.PIPE
        )
    except subprocess.CalledProcessError as exc:
        print(f"❌ ffmpeg error (code {exc.returncode}): {' '.join(cmd)}")
        sys.exit(exc.returncode)

```

This guarantees that any FFmpeg failure produces a clean exit with a descriptive message rather than a traceback.

### Implementing Graceful Fallbacks for Missing Overlays

Overlays are resolved with `resolve_path` at lines 515-520 but are not validated before being added to the filter graph. Add existence checks to skip missing overlays with a warning:

```python
def load_overlays(overlays: list[dict], edit_dir: Path) -> list[dict]:
    """Filter out missing overlay files before compositing."""
    valid = []
    for ov in overlays:
        ov_path = resolve_path(ov["file"], edit_dir)
        if ov_path.is_file():
            valid.append(ov)
        else:
            print(f"⚠️  Skipping missing overlay: {ov_path}")
    return valid

```

### Capturing Stderr for Debugging

The current commands discard stdout. For post-mortem analysis, capture stderr to a log file by modifying the `subprocess.run` calls:

```python
subprocess.run(
    cmd, 
    check=True, 
    stdout=subprocess.DEVNULL,
    stderr=open("ffmpeg_error.log", "a")
)

```

This preserves FFmpeg's detailed error output for troubleshooting codec or filter graph issues.

### Handling Loudness Normalization Failures

The loudness normalization at lines 297-340 implements a two-pass measurement that can fail. The code already falls back to a one-pass approximation by calling `apply_loudnorm_two_pass(..., preview=True)` when measurement fails. Ensure this fallback path is preserved and consider logging a warning when the approximation is used.

## Production-Ready Code Examples

Drop these complete snippets into your workflow to catch typical video-related errors.

**Verify sources before rendering:**

```python
def verify_sources(edl: dict, edit_dir: Path) -> None:
    missing = []
    for name, path_str in edl["sources"].items():
        path = resolve_path(path_str, edit_dir)
        if not path.is_file():
            missing.append(str(path))
    if missing:
        sys.exit(f"❌ Missing source files: {', '.join(missing)}")

```

**Safe wrapper for all FFmpeg calls:**

```python
def run_ffmpeg(cmd: list[str], quiet: bool = False) -> None:
    try:
        subprocess.run(cmd, check=True,
                       stdout=subprocess.DEVNULL,
                       stderr=subprocess.PIPE)
    except subprocess.CalledProcessError as exc:
        print(f"❌ ffmpeg error (code {exc.returncode}): {' '.join(cmd)}")
        sys.exit(exc.returncode)

```

**Graceful overlay handling:**

```python
def load_overlays(overlays: list[dict], edit_dir: Path) -> list[dict]:
    valid = []
    for ov in overlays:
        ov_path = resolve_path(ov["file"], edit_dir)
        if ov_path.is_file():
            valid.append(ov)
        else:
            print(f"⚠️  Skipping missing overlay: {ov_path}")
    return valid

```

## Summary

- **video-use** delegates all video processing to FFmpeg via `subprocess.run`, making `CalledProcessError` the primary failure mode.
- Critical paths in [`helpers/render.py`](https://github.com/browser-use/video-use/blob/main/helpers/render.py) (lines 66-82, 161-210, 506-570) lack exception handling and will crash with stack traces on any FFmpeg error.
- HDR and portrait detection (lines 121-147) already implement graceful fallbacks by returning `False` on `ffprobe` failures.
- Pre-flight validation of EDL sources prevents late-stage crashes during segment extraction.
- Wrapping `subprocess.run` calls with `try/except` blocks provides user-friendly error messages and controlled exit codes for CI/CD pipelines.
- Validating overlay files after `resolve_path` prevents filter graph construction errors.

## Frequently Asked Questions

### What error does video-use throw when FFmpeg fails?

When FFmpeg returns a non-zero exit code, **video-use** raises a Python `subprocess.CalledProcessError` because the code uses `subprocess.run(..., check=True)` without exception handling in functions like `extract_segment` and `concat_segments`. This results in a raw stack trace and immediate process termination.

### How do I prevent video-use from crashing on missing source files?

Insert a pre-flight check that validates every path in `edl["sources"]` before calling the render functions. The current codebase only validates the EDL file itself at lines 78-80, not the media files it references. Use the `verify_sources` pattern shown above to catch missing files before FFmpeg execution begins.

### Can I skip HDR detection if ffprobe fails?

Yes. The existing code at lines 121-132 already handles `ffprobe` failures by wrapping the call in a `try/except` block that returns `False`, causing the pipeline to treat the video as SDR. You can add a warning log inside the except block to notify users while allowing the process to continue.

### Where should I add error handling in the video-use pipeline?

Focus on [`helpers/render.py`](https://github.com/browser-use/video-use/blob/main/helpers/render.py), specifically:
- **Lines 66-82**: Wrap the concat demuxer call.
- **Lines 161-210**: Wrap the segment extraction FFmpeg command.
- **Lines 515-520**: Validate overlay file existence after path resolution.
- **Lines 506-570**: Wrap the final compositing command.

These locations represent the highest-risk subprocess calls where missing files or invalid parameters will cause immediate failures.