# How `claude-video` Handles API Failures from Whisper Providers: Retry Logic and Error Recovery

> Discover how claude-video handles API failures from Whisper providers with robust retry logic and error recovery. Learn about its strategies for transient network errors and persistent issue escalation.

- Repository: [bradautomates/claude-video](https://github.com/bradautomates/claude-video)
- Tags: error-handling
- Published: 2026-07-12

---

**The `claude-video` repository implements a defensive retry strategy that catches transient network errors like `urllib.error.URLError` and `TimeoutError`, attempts recovery up to `MAX_ATTEMPTS`, and escalates persistent failures via `SystemExit` with diagnostic context.**

The `bradautomates/claude-video` project integrates with Whisper providers (Groq and OpenAI) to generate video transcripts. Robust error handling is critical when dealing with external transcription APIs that may experience transient network issues or rate limiting.

## Error Handling Architecture

The transcription logic in [`skills/watch/scripts/whisper.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/whisper.py) employs a multi-layered defense strategy that distinguishes between recoverable transient failures and permanent errors requiring user intervention.

### Early Validation: Preventing Calls Without Credentials

Before initiating any network requests, the script validates the presence of required API keys. According to the source code in [`skills/watch/scripts/whisper.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/whisper.py), if neither `GROQ_API_KEY` nor `OPENAI_API_KEY` is configured, the function exits immediately at line 432:

```python
raise SystemExit("No Whisper API key available…")

```

This early failure prevents wasted compute cycles and provides clear guidance to the user to configure their environment variables.

### Transient Error Recovery: The MAX_ATTEMPTS Loop

The core request logic wraps `urllib.request.urlopen` in a retry loop governed by the `MAX_ATTEMPTS` constant. When interacting with Whisper providers, the code anticipates intermittent network issues by catching specific exception types at line 267:

```python
except (urllib.error.URLError, TimeoutError, ConnectionResetError, OSError) as exc:

```

For each caught exception, the script logs the error details and retries the request. This approach handles transient DNS failures, temporary connection resets, and timeout scenarios common in cloud API interactions.

### Escalating Unrecoverable HTTP Failures

When the retry limit is exhausted, the script aborts with a descriptive `SystemExit` message. At lines 269-274, the error handling constructs a detailed failure message that includes the original exception and any HTTP response details:

```python
raise SystemExit(f"Whisper request failed: {exc}{detail}")

```

If the loop completes all iterations without success, line 305 provides a final summary error:

```python
raise SystemExit(f"Whisper request failed after {MAX_ATTEMPTS} attempts: {last_exc}{last_detail}")

```

This ensures that calling processes in [`skills/watch/scripts/watch.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/watch.py) receive explicit notification that transcription is impossible, allowing the CLI to surface the error to the end user.

### Response Validation: JSON Parsing and Empty Transcripts

Successful HTTP responses undergo strict validation. The script attempts to parse the JSON payload immediately after the network call. If the provider returns non-JSON data (such as an HTML error page), lines 301-302 catch the `json.JSONDecodeError` and exit:

```python
raise SystemExit(f"Whisper returned non‑JSON response: {exc}: {payload[:200]}")

```

Additionally, the script validates that the transcription actually contains data. At line 462, if the decoded JSON lacks transcript segments, the code raises:

```python
raise SystemExit("Whisper returned no transcript segments")

```

This prevents downstream processing of empty results and alerts the user to potential issues with the audio input or provider configuration.

## Implementation Example

When integrating the Whisper functionality into custom workflows, wrap the `transcribe_whisper` call to handle the `SystemExit` exceptions gracefully:

```python
from skills.watch.scripts.whisper import transcribe_whisper

try:
    segments = transcribe_whisper(audio_bytes, backend="groq")
except SystemExit as e:
    print(f"Transcription aborted: {e}")
    segments = []

```

For command-line usage, the `/watch` skill automatically propagates these errors:

```bash
watch https://www.youtube.com/watch?v=example

# If Whisper fails after retries: "Whisper request failed after 3 attempts: ..."

```

## Summary

- **Early validation** prevents API calls when `GROQ_API_KEY` or `OPENAI_API_KEY` is missing, failing fast at line 432.
- **Transient error handling** catches `urllib.error.URLError`, `TimeoutError`, `ConnectionResetError`, and `OSError` at line 267, enabling automatic retries up to `MAX_ATTEMPTS`.
- **Hard failure escalation** occurs via `SystemExit` at lines 269-274 and 305, providing diagnostic context including the original exception and accumulated error details.
- **Response validation** guards against malformed JSON (lines 301-302) and empty transcript segments (line 462), ensuring only valid data proceeds to downstream processing.

## Frequently Asked Questions

### What happens when the Whisper API returns a transient network error?

The script catches specific exceptions including `urllib.error.URLError`, `TimeoutError`, `ConnectionResetError`, and `OSError` at line 267, logs the error, and retries the request until it succeeds or reaches `MAX_ATTEMPTS`. This handles temporary DNS failures, connection drops, and timeout scenarios without aborting the entire workflow.

### How many retry attempts does the script make before giving up?

The retry limit is controlled by the `MAX_ATTEMPTS` constant defined in [`skills/watch/scripts/whisper.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/whisper.py). When this threshold is exceeded, the script raises `SystemExit` at line 305 with a message containing the last exception encountered and any accumulated detail from the response.

### What error message appears when the API returns invalid JSON?

If the Whisper provider returns a non-JSON response (such as an HTML error page or malformed payload), the script catches `json.JSONDecodeError` at lines 301-302 and exits with `SystemExit`, displaying the parsing error and the first 200 characters of the raw payload for debugging purposes.

### How does the script handle missing API keys?

Before attempting any network requests, the script checks for the presence of `GROQ_API_KEY` or `OPENAI_API_KEY`. If neither is found, it raises `SystemExit` at line 432 with a message indicating that no Whisper API key is available, prompting the user to configure their credentials.