ytdl-org/youtube-dl · error · ExtractorError
Unable to download video %s
Error message
Unable to download video %s
What it means
The ivi.ru extractor's generic per-video failure: the light API answered with an error object whose origin was not the geo or not-exist cases and no dependency/bundling issue applied, so the default 'Unable to download video %s' (optionally suffixed with the server's message) is raised as an expected ExtractorError.
Source
Thrown at youtube_dl/extractor/ivi.py:153
message = error.get('message') or error.get('user_message')
extractor_msg = 'Unable to download video %s'
if origin == 'NotAllowedForLocation':
self.raise_geo_restricted(message, self._GEO_COUNTRIES)
elif origin == 'NoRedisValidData':
extractor_msg = 'Video %s does not exist'
elif site == 353:
continue
elif bundled:
raise ExtractorError(
'This feature does not work from bundled exe. Run youtube-dl from sources.',
expected=True)
elif not pycryptodomex_found:
raise ExtractorError(
'pycryptodomex not found. Please install it.',
expected=True)
elif message:
extractor_msg += ': ' + message
raise ExtractorError(extractor_msg % video_id, expected=True)
else:
break
result = video_json['result']
title = result['title']
quality = qualities(self._KNOWN_FORMATS)
formats = []
for f in result.get('files', []):
f_url = f.get('url')
content_format = f.get('content_format')
if not f_url or '-MDRM-' in content_format or '-FPS-' in content_format:
continue
formats.append({
'url': f_url,
'format_id': content_format,
'quality': quality(content_format),View on GitHub (pinned to 956b8c5855)
Solutions
- Read the appended server message (if any) - it identifies the actual rejection reason.
- Confirm the video plays for free in a browser from your region.
- Update youtube-dl/yt-dlp for current ivi API error semantics.
Defensive patterns
Strategy: try-catch
Try / catch
try:
ydl.extract_info(ivi_url)
except ExtractorError as e:
if str(e).startswith('Unable to download video'):
# check for paid-content/geo hints in the tail of the message, else retry once
handle_ivi_rejection(str(e)) Prevention
- Capture the server message suffix to classify paid vs transient failures.
- Confirm free-tier availability of ivi content before batch jobs.
- Keep extractor current; ivi error origins evolve.
When it happens
Trigger: POST to ivi's _LIGHT_URL (contentdelegation) returning {'error': {...}} with an unknown origin - e.g. 'CROSS_DEVICE_LIMIT', paid-content errors, or malformed/expired content IDs that still resolve to a generic error.
Common situations: Paid ivi.ru content without a subscription, content removed between listing and playback, or server-side API changes altering the error envelope.
Related errors
- message
- Unable to load data. Error code: %s
- %s returns error %d
- This video is DRM protected.
- %s said: %s
AI-assisted analysis of ytdl-org/youtube-dl@956b8c5855 (2026-08-14).
Data as JSON: /api/errors/1b6d9d559c914f96.
Report an issue: GitHub.