How `claude-video` Handles API Failures from Whisper Providers: Retry Logic and Error Recovery
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 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, if neither GROQ_API_KEY nor OPENAI_API_KEY is configured, the function exits immediately at line 432:
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:
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:
raise SystemExit(f"Whisper request failed: {exc}{detail}")
If the loop completes all iterations without success, line 305 provides a final summary error:
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 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:
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:
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:
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:
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_KEYorOPENAI_API_KEYis missing, failing fast at line 432. - Transient error handling catches
urllib.error.URLError,TimeoutError,ConnectionResetError, andOSErrorat line 267, enabling automatic retries up toMAX_ATTEMPTS. - Hard failure escalation occurs via
SystemExitat 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. 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.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →