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

  1. 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).
  2. Use a Belgian proxy/VPN for INVALID_LOCATION-class errors: --proxy.
  3. Update to yt-dlp, whose VRT handling is maintained.
  4. 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

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


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