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

  1. 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.
  2. 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.
  3. Upgrade youtube-dl — Vevo auth changes are typically patched upstream.
  4. 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

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.