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
- Read the propagated error_description — it distinguishes missing video from auth/signature failure.
- If all Vice URLs fail, diff the browser's preplay request query against the extractor's 'query' dict and update the signing parameters.
- Confirm the locale extracted from the URL still matches a valid vms.vice.com path segment.
- 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
- If the error fires on all Vice URLs, fix the preplay query signature, not the URLs.
- Log the HTTP code alongside the message (400 vs 401) when instrumenting.
- Keep the extractor updated — Vice's VMS signing parameters change periodically.
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.