yt-dlp/yt-dlp · error · ExtractorError
{IE_NAME} returned error: {error}
Error message
{IE_NAME} returned error: {error} What it means
Raised by UstreamIE._real_extract when the JSON from api.ustream.tv/videos/<id>.json contains a non-empty 'error' key; the API's own error text (e.g. 'not found') is appended to the message. The HTTP layer may still return 200 here, so this is the extractor's application-level check after a successful download. Expected=True.
Source
Thrown at yt_dlp/extractor/ustream.py:181
video_id = m.group('id')
desktop_url = 'http://www.ustream.tv/recorded/' + video_id
return self.url_result(desktop_url, 'Ustream')
if m.group('type') == 'embed':
video_id = m.group('id')
webpage = self._download_webpage(url, video_id)
content_video_ids = self._parse_json(self._search_regex(
r'ustream\.vars\.offAirContentVideoIds=([^;]+);', webpage,
'content video IDs'), video_id)
return self.playlist_result(
(self.url_result('http://www.ustream.tv/recorded/' + u, 'Ustream') for u in content_video_ids),
video_id)
params = self._download_json(
f'https://api.ustream.tv/videos/{video_id}.json', video_id)
error = params.get('error')
if error:
raise ExtractorError(
f'{self.IE_NAME} returned error: {error}', expected=True)
video = params['video']
title = video['title']
filesize = float_or_none(video.get('file_size'))
formats = [{
'id': video_id,
'url': video_url,
'ext': format_id,
'filesize': filesize,
} for format_id, video_url in video['media_urls'].items() if video_url]
if not formats:
hls_streams = self._get_streams(url, video_id, app_id_ver=(11, 2))
if hls_streams:
# m3u8_native leads to intermittent ContentTooShortErrorView on GitHub (pinned to 81ecd58b13)
Solutions
- Open the URL in a browser to confirm the recording still exists and is public
- If the channel is live, use the live URL form instead of /recorded/<id>
- Remove dead ids from automated queues and log them instead of retrying
- Update yt-dlp in case the API endpoint moved after platform changes
Defensive patterns
Strategy: try-catch
Type guard
def is_ustream_api_error(e: Exception) -> bool:
return isinstance(e, ExtractorError) and 'Ustream returned error' in str(e) Try / catch
try:
ydl.extract_info(url, download=True)
except ExtractorError as e:
if 'Ustream returned error' in str(e):
archive_dead_recording(video_id) # API-level rejection is terminal
else:
raise Prevention
- Treat API error payloads as permanent: remove the id from queues instead of retrying
- Validate that /recorded/<id> pages still exist in a browser before batch runs
When it happens
Trigger: Extracting a ustream.tv/recorded/<id> (or IBM Video Streaming) URL whose API responds with an error object — deleted recordings, private videos, or invalid ids.
Common situations: Old recorded URLs after Ustream's IBM migration removed content; deleted or unlisted recordings; mistyped numeric ids; playlists referencing dead recordings.
Related errors
- {self.IE_NAME} said: {err.get("code")} - {err.get("message")
- {self.IE_NAME} said: {error_msg}
- tvigle returned error: {error_message}
- {msg}
- {IE_NAME} said: {msg}
AI-assisted analysis of yt-dlp/yt-dlp@81ecd58b13 (2026-08-22).
Data as JSON: /api/errors/b6989d9d6bca49e5.
Report an issue: GitHub.