ytdl-org/youtube-dl · error · ExtractorError

%s said: %s

Error message

%s said: %s

What it means

Raised by the Vice extractor when the vms.vice.com preplay call fails with HTTP 400 or 401 and the JSON body contains error_description or details; that text is re-raised with the extractor name. 401 typically means the signed query (platform/rn signature) was rejected; 400 means bad video id/locale. expected=True.

Source

Thrown at youtube_dl/extractor/vice.py:160

        exp = int(time.time()) + 1440

        query.update({
            'exp': exp,
            'sign': hashlib.sha512(('%s:GET:%d' % (video_id, exp)).encode()).hexdigest(),
            'skipadstitching': 1,
            'platform': 'desktop',
            'rn': random.randint(10000, 100000),
        })

        try:
            preplay = self._download_json(
                'https://vms.vice.com/%s/video/preplay/%s' % (locale, video_id),
                video_id, query=query)
        except ExtractorError as e:
            if isinstance(e.cause, compat_HTTPError) and e.cause.code in (400, 401):
                error = json.loads(e.cause.read().decode())
                error_message = error.get('error_description') or error['details']
                raise ExtractorError('%s said: %s' % (
                    self.IE_NAME, error_message), expected=True)
            raise

        video_data = preplay['video']
        formats = self._extract_m3u8_formats(
            preplay['playURL'], video_id, 'mp4', 'm3u8_native')
        self._sort_formats(formats)
        episode = video_data.get('episode') or {}
        channel = video_data.get('channel') or {}
        season = video_data.get('season') or {}

        subtitles = {}
        for subtitle in preplay.get('subtitleURLs', []):
            cc_url = subtitle.get('url')
            if not cc_url:
                continue
            language_code = try_get(subtitle, lambda x: x['languages'][0]['language_code'], compat_str) or 'en'
            subtitles.setdefault(language_code, []).append({

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Read the propagated error_description — it distinguishes missing video from auth/signature failure.
  2. If all Vice URLs fail, diff the browser's preplay request query against the extractor's 'query' dict and update the signing parameters.
  3. Confirm the locale extracted from the URL still matches a valid vms.vice.com path segment.
  4. Upgrade youtube-dl to pick up upstream fixes to the preplay query.
Defensive patterns

Strategy: try-catch

Try / catch

try:
    ydl.extract_info(url)
except ExtractorError as e:
    if e.expected and 'said:' in str(e):
        log_skip(url, str(e))  # 400 = bad id/locale, 401 = signature rejected — both need code/config change, not retry
    raise

Prevention

When it happens

Trigger: Calling the preplay endpoint for a removed video, an unknown locale segment, or when the ad/signature parameters in 'query' no longer satisfy Vice's VMS validation, yielding e.cause.code in (400, 401).

Common situations: Vice changed the required preplay signature parameters (the query dict with 'platform': 'desktop', 'rn': random); videos geo- or age-restricted; site restructures after Vice Media's domain consolidations.

Related errors


AI-assisted analysis of ytdl-org/youtube-dl@956b8c5855 (2026-08-14). Data as JSON: /api/errors/9241abb6d9f4c6b4. Report an issue: GitHub.