How Error Handling Works in bradautomates/claude-video: Three Patterns for Resilient Video Processing

claude-video implements a three-tier error handling strategy using SystemExit for critical failures, try/except blocks for recoverable errors, and guard clauses for input validation, ensuring the pipeline degrades gracefully while logging all diagnostics to stderr.

The bradautomates/claude-video repository processes video content through external tools like yt-dlp and OpenAI's Whisper, requiring robust error handling to manage missing dependencies, network failures, and malformed subtitle data. Analyzing the source code reveals a deliberate architectural choice to distinguish between fatal errors that abort execution and recoverable errors that allow partial output generation. This approach ensures that users receive frame extractions and transcript segments even when secondary transcription services fail.

Core Error Handling Patterns

Critical Failures with SystemExit

When the application encounters missing external dependencies or fails to generate required output files, it raises SystemExit to terminate immediately with a clear diagnostic message. This pattern appears throughout skills/watch/scripts/download.py and skills/watch/scripts/frames.py to enforce environmental requirements.

In skills/watch/scripts/download.py (lines 20-31), the code validates that yt-dlp exists before attempting downloads:

if shutil.which("yt-dlp") is None:
    raise SystemExit("yt-dlp is not installed. Install with: brew install yt-dlp")

Similarly, if the video download subprocess completes but produces no output file, the script aborts with the subprocess exit code (lines 120-122 and 146-152). The same pattern applies in skills/watch/scripts/frames.py where missing ffmpeg installations trigger immediate termination, as frame extraction represents a critical dependency for visual output.

Graceful Degradation with Try/Except Blocks

For non-fatal errors that should not interrupt the entire workflow, claude-video wraps risky operations in try/except blocks and logs warnings to stderr. This pattern dominates skills/watch/scripts/watch.py, particularly around subtitle parsing and Whisper API calls.

When parsing WebVTT subtitles fails due to malformed JSON or format issues (lines 100-108), the handler catches the exception and continues execution:

try:
    transcript_segments = parse_vtt(dl["subtitle_path"])
except Exception as exc:
    print(f"[watch] subtitle parse failed: {exc}", file=sys.stderr)
    transcript_segments = []

The pipeline implements similar protection for Whisper transcription (lines 130-138 and 250-254), catching API failures or parsing errors and falling back to empty transcript arrays while preserving extracted frames for the final report.

Defensive Validation with Guard Clauses

Before invoking expensive operations, guard clauses validate user inputs and abort early with helpful messages. Located primarily in skills/watch/scripts/watch.py (lines 43-46 and 78-80), these checks prevent invalid states from propagating through the pipeline.

For example, the script validates the --max-frames parameter to ensure positive integers:

if max_frames is not None and max_frames < 1:
    raise SystemExit("--max-frames must be greater than zero")

Additional validation ensures temporal bounds make sense (verifying start time precedes end time) and calculates detail budgets only when sufficient frames exist (lines 117-119).

Error Flow Through the Video Processing Pipeline

Understanding how error handling in bradautomates/claude-video operates requires tracing the execution flow through distinct pipeline stages:

  1. Argument validation – Guard clauses check CLI inputs immediately upon entry to watch.py, raising SystemExit for illegal combinations like negative timestamps or zero max-frames.

  2. Dependency verificationdownload.fetch_captions validates yt-dlp availability; missing binaries trigger SystemExit before any network operations begin.

  3. Subtitle acquisition – The metadata fetch attempts to retrieve captions. If yt-dlp succeeds but produces unparseable WebVTT, the try/except block captures the error, logs to stderr, and proceeds with an empty transcript array.

  4. Video download – Critical failures here (network timeouts, unavailable videos) raise SystemExit with the subprocess return code, as the pipeline cannot proceed without video data.

  5. Transcription fallback – When subtitles fail and Whisper is enabled, the API call is wrapped in try/except SystemExit handling. If Whisper fails, the warning is logged but frame analysis continues.

  6. Frame extraction – Errors in skills/watch/scripts/frames.py surface as SystemExit because ffmpeg represents a hard dependency for visual processing.

Centralized Logging Strategy

All error messages route exclusively to stderr using print(..., file=sys.stderr), while the generated markdown report flows to stdout. This separation keeps diagnostic noise out of the final output consumed by Claude or other downstream agents. The pattern appears consistently across skills/watch/scripts/watch.py, download.py, and whisper.py, ensuring that partial failures (like missing transcripts) do not corrupt the structured markdown output containing successfully extracted frames.

Key Implementation Files

  • skills/watch/scripts/download.py – Validates external dependencies via shutil.which() checks and raises SystemExit when yt-dlp is missing or when downloads fail to produce expected output files.

  • skills/watch/scripts/watch.py – Central orchestration file containing argument guard clauses (lines 43-46, 78-80), subtitle parsing exception handlers (lines 100-108, 240-247), and Whisper fallback logic (lines 130-138, 250-254).

  • skills/watch/scripts/whisper.py – Loads API keys from environment variables and raises SystemExit if OPENAI_API_KEY is missing, protecting against invalid API calls that would waste compute cycles.

  • skills/watch/scripts/frames.py – Validates ffmpeg availability and aborts on extraction errors that would produce empty frame sets.

Summary

  • SystemExit terminates the skill immediately for unrecoverable errors like missing yt-dlp, ffmpeg, or failed video downloads.
  • Try/except blocks in watch.py catch subtitle parsing and Whisper API failures, logging warnings to stderr while allowing frame extraction to complete.
  • Guard clauses validate inputs early (time ranges, frame counts) with explicit error messages before processing begins.
  • Stderr isolation ensures diagnostic messages do not contaminate the markdown report sent to stdout for Claude consumption.
  • The architecture prioritizes partial results over total failure, ensuring users receive visual frame analysis even when transcription services are unavailable.

Frequently Asked Questions

What happens if yt-dlp is not installed when running claude-video?

The skills/watch/scripts/download.py module checks for the yt-dlp binary using shutil.which() before any download operations. If the tool is missing, it raises SystemExit with a clear installation message, preventing the pipeline from attempting network operations that would certainly fail.

Does claude-video continue processing if subtitle parsing fails?

Yes. Subtitle parsing in skills/watch/scripts/watch.py is wrapped in try/except blocks that catch parsing exceptions, log the error to stderr, and set the transcript to an empty list. The pipeline continues to frame extraction and Whisper fallback transcription, ensuring you still receive visual analysis even with corrupted caption data.

How are invalid command-line arguments handled in claude-video?

Guard clauses in watch.py validate arguments like --max-frames and time ranges before processing begins. Invalid inputs (such as negative numbers or end-times before start-times) trigger SystemExit with descriptive error messages, aborting immediately rather than failing midway through expensive video processing.

Where do error messages get logged in the claude-video skill?

All error diagnostics print to stderr using print(..., file=sys.stderr), while the markdown report generated for Claude routes to stdout. This architectural separation ensures that error warnings and stack traces do not corrupt the structured output intended for AI consumption or downstream processing.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →