ytdl-org/youtube-dl · error · ExtractorError
%s said: %s
Error message
%s said: %s
What it means
Raised by the Vevo extractor's _call_api when an HTTP error from apiv2.vevo.com carries a JSON body with an 'errors' list; the messages are joined and re-raised with the extractor name. It converts a transport-level HTTPError into an expected, human-readable site error (geo-block, video not found, token problems).
Source
Thrown at youtube_dl/extractor/vevo.py:187
headers={
'Content-Type': 'application/json',
})
if re.search(r'(?i)THIS PAGE IS CURRENTLY UNAVAILABLE IN YOUR REGION', webpage):
self.raise_geo_restricted(
'%s said: This page is currently unavailable in your region' % self.IE_NAME)
auth_info = self._parse_json(webpage, video_id)
self._api_url_template = self.http_scheme() + '//apiv2.vevo.com/%s?token=' + auth_info['legacy_token']
def _call_api(self, path, *args, **kwargs):
try:
data = self._download_json(self._api_url_template % path, *args, **kwargs)
except ExtractorError as e:
if isinstance(e.cause, compat_HTTPError):
errors = self._parse_json(e.cause.read().decode(), None)['errors']
error_message = ', '.join([error['message'] for error in errors])
raise ExtractorError('%s said: %s' % (self.IE_NAME, error_message), expected=True)
raise
return data
def _real_extract(self, url):
video_id = self._match_id(url)
self._initialize_api(video_id)
video_info = self._call_api(
'video/%s' % video_id, video_id, 'Downloading api video info',
'Failed to download video info')
video_versions = self._call_api(
'video/%s/streams' % video_id, video_id,
'Downloading video versions info',
'Failed to download video versions info',
fatal=False)
View on GitHub (pinned to 956b8c5855)
Solutions
- Read the propagated message — 'This page is currently unavailable in your region' vs 'not found' tells you whether a VPN/relay helps or the video is gone.
- If every video fails, the legacy-token bootstrap broke: re-check _initialize_api against the current vevo.com page (isolate/auth JSON) and update it.
- Upgrade youtube-dl — Vevo auth changes are typically patched upstream.
- Handle it as expected=True: log and continue, do not retry blindly.
Defensive patterns
Strategy: try-catch
Try / catch
try:
info = ydl.extract_info(url)
except ExtractorError as e:
if e.expected and 'Vevo said:' in str(e):
msg = str(e)
if 'region' in msg:
retry_via_proxy(url) # geo-block is proxy-solvable
else:
log_skip(url, msg) # deleted/not found is permanent
else:
raise Prevention
- Distinguish region-locked vs deleted from the propagated API message before choosing a remedy.
- If every Vevo URL fails, suspect the legacy-token bootstrap, not the videos.
- Rate-limit API-backed extractors to avoid throttle error bodies.
When it happens
Trigger: Any _call_api request (e.g. 'video/<id>') returning 4xx whose body parses as {"errors": [{"message": ...}]}; common for region-locked videos or after the legacy token bootstrap (auth_info['legacy_token']) expires or is rejected.
Common situations: Region-restricted videos outside the US/UK; Vevo API v2 deprecation or token changes breaking _initialize_api; deleted videos; clients hammering the API and getting throttled with error bodies.
Related errors
AI-assisted analysis of ytdl-org/youtube-dl@956b8c5855 (2026-08-14).
Data as JSON: /api/errors/996d5401b35e9191.
Report an issue: GitHub.