ytdl-org/youtube-dl · error · ExtractorError

json.loads(e.cause.read().decode())['message']

Error message

json.loads(e.cause.read().decode())['message']

What it means

VRV OAuth-signature error path: when the signed API request (HMAC-SHA1 over base_url+query with oAuthSecret & token secret) returns HTTP 401, the extractor reads the error body, parses it as JSON, and re-raises its 'message' field with expected=True. The placeholder stands for that parsed message (e.g. 'Invalid token').

Source

Thrown at youtube_dl/extractor/vrv.py:62

        headers = self.geo_verification_headers()
        if data:
            data = json.dumps(data).encode()
            headers['Content-Type'] = 'application/json'
        base_string = '&'.join([
            'POST' if data else 'GET',
            compat_urllib_parse.quote(base_url, ''),
            compat_urllib_parse.quote(encoded_query, '')])
        oauth_signature = base64.b64encode(hmac.new(
            (self._API_PARAMS['oAuthSecret'] + '&' + self._TOKEN_SECRET).encode('ascii'),
            base_string.encode(), hashlib.sha1).digest()).decode()
        encoded_query += '&oauth_signature=' + compat_urllib_parse.quote(oauth_signature, '')
        try:
            return self._download_json(
                '?'.join([base_url, encoded_query]), video_id,
                note='Downloading %s JSON metadata' % note, headers=headers, data=data)
        except ExtractorError as e:
            if isinstance(e.cause, compat_HTTPError) and e.cause.code == 401:
                raise ExtractorError(json.loads(e.cause.read().decode())['message'], expected=True)
            raise

    def _call_cms(self, path, video_id, note):
        if not self._CMS_SIGNING:
            index = self._call_api('index', video_id, 'CMS Signing')
            self._CMS_SIGNING = index.get('cms_signing') or {}
            if not self._CMS_SIGNING:
                for signing_policy in index.get('signing_policies', []):
                    signing_path = signing_policy.get('path')
                    if signing_path and signing_path.startswith('/cms/'):
                        name, value = signing_policy.get('name'), signing_policy.get('value')
                        if name and value:
                            self._CMS_SIGNING[name] = value
        return self._download_json(
            self._API_DOMAIN + path, video_id, query=self._CMS_SIGNING,
            note='Downloading %s JSON metadata' % note, headers=self.geo_verification_headers())

    def _get_cms_resource(self, resource_key, video_id):

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Re-authenticate: pass fresh credentials/cookies so a new token secret is derived
  2. Check the parsed message text — 'Invalid token' vs other messages point to different fixes
  3. Ensure requests come from a supported region (VRV is US/Canada) with a sane system clock
Defensive patterns

Strategy: retry

Try / catch

from youtube_dl.utils import ExtractorError
try:
    ydl.extract_info(url)
except ExtractorError as e:
    if 'token' in str(e).lower():
        reauth_vrv()  # obtain fresh token secret
        ydl.extract_info(url)  # single retry with new credentials

Prevention

When it happens

Trigger: Calling the VRV API with a stale/invalid session token or bad OAuth credentials, so the server answers 401 and the except-branch converts e.cause (compat_HTTPError) into the JSON message.

Common situations: Expired VRV session/auth token after re-login requirements; region outside US/Canada where VRV blocks auth; clock skew breaking the OAuth signature (timestamp/nonce).

Related errors


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