ytdl-org/youtube-dl · error · ExtractorError
data.get('message') or code
Error message
data.get('message') or code What it means
Raised by CanvasIE (VRT.be) when the REST video endpoint responds without a 'title'. The request is made with expected_status=400, so HTTP 400 error bodies are parsed normally; if code is AUTHENTICATION_REQUIRED the extractor raises login-required, INVALID_LOCATION raises geo-restricted (BE only), and anything else raises ExtractorError with data['message'] or the code itself.
Source
Thrown at youtube_dl/extractor/canvas.py:80
if not data:
headers = self.geo_verification_headers()
headers.update({'Content-Type': 'application/json'})
token = self._download_json(
'%s/tokens' % self._REST_API_BASE, video_id,
'Downloading token', data=b'', headers=headers)['vrtPlayerToken']
data = self._download_json(
'%s/videos/%s' % (self._REST_API_BASE, video_id),
video_id, 'Downloading video JSON', query={
'vrtPlayerToken': token,
'client': '%s@PROD' % site_id,
}, expected_status=400)
if not data.get('title'):
code = data.get('code')
if code == 'AUTHENTICATION_REQUIRED':
self.raise_login_required()
elif code == 'INVALID_LOCATION':
self.raise_geo_restricted(countries=['BE'])
raise ExtractorError(data.get('message') or code, expected=True)
title = data['title']
description = data.get('description')
formats = []
for target in data['targetUrls']:
format_url, format_type = url_or_none(target.get('url')), str_or_none(target.get('type'))
if not format_url or not format_type:
continue
format_type = format_type.upper()
if format_type in self._HLS_ENTRY_PROTOCOLS_MAP:
formats.extend(self._extract_m3u8_formats(
format_url, video_id, 'mp4', self._HLS_ENTRY_PROTOCOLS_MAP[format_type],
m3u8_id=format_type, fatal=False))
elif format_type == 'HDS':
formats.extend(self._extract_f4m_formats(
format_url, video_id, f4m_id=format_type, fatal=False))
elif format_type == 'MPEG_DASH':View on GitHub (pinned to 956b8c5855)
Solutions
- If the message indicates login is needed, pass credentials so raise_login_required paths can be used (or use VRT NU with an account-specific extractor/yt-dlp).
- Use a Belgian proxy/VPN for INVALID_LOCATION-class errors: --proxy.
- Update to yt-dlp, whose VRT handling is maintained.
- Check the exact 'message'/'code' in the exception text — it is the raw API response and pinpoints the cause.
Example fix
try:
info = ydl.extract_info(vrt_url, download=False)
except ExtractorError as e:
if 'INVALID_LOCATION' in str(e) or 'geo' in str(e).lower():
info = ydl.extract_info(vrt_url, download=False, proxy='http://be-proxy:8080')
else:
raise Defensive patterns
Strategy: try-catch
Try / catch
from youtube_dl.utils import ExtractorError, GeoRestrictedError
try:
info = ydl.extract_info(url, download=False)
except GeoRestrictedError:
info = ydl.extract_info(url, download=False, geo_bypass_country='BE')
except ExtractorError as e:
if 'AUTHENTICATION_REQUIRED' in str(e):
raise NeedsLogin(url)
raise Prevention
- Surface the raw VRT 'message'/'code' to classify failures (login vs geo vs missing).
- Use a Belgian exit node for VRT content.
- Provide credentials for login-gated VRT items.
When it happens
Trigger: API responses with codes other than the two handled ones — e.g. VIDEO_NOT_FOUND, expired vrtPlayerToken producing a different error code, or generic API failures. The token is fetched anonymously, so token-bound failures surface here.
Common situations: Downloading VRT content from outside Belgium (INVALID_LOCATION is handled as geo, but sibling codes are not); videos that require a VRT account; changed API error schema in a stale youtube-dl.
Related errors
- %s said: %s
- error['description']
- %s returned error: %s
- %s said: %s
- This video is only available after 20:00
AI-assisted analysis of ytdl-org/youtube-dl@956b8c5855 (2026-08-14).
Data as JSON: /api/errors/f833dffa332ac97a.
Report an issue: GitHub.