{"record":{"id":"b309837434a68a26","repo":"ytdl-org/youtube-dl","slug":"json-loads-e-cause-read-decode-message","errorCode":null,"errorMessage":"json.loads(e.cause.read().decode())['message']","messagePattern":"json\\.loads\\(e\\.cause\\.read\\(\\)\\.decode\\(\\)\\)\\['message'\\]","errorType":"exception","errorClass":"ExtractorError","httpStatus":401,"severity":"error","filePath":"youtube_dl/extractor/vrv.py","lineNumber":62,"sourceCode":"        headers = self.geo_verification_headers()\n        if data:\n            data = json.dumps(data).encode()\n            headers['Content-Type'] = 'application/json'\n        base_string = '&'.join([\n            'POST' if data else 'GET',\n            compat_urllib_parse.quote(base_url, ''),\n            compat_urllib_parse.quote(encoded_query, '')])\n        oauth_signature = base64.b64encode(hmac.new(\n            (self._API_PARAMS['oAuthSecret'] + '&' + self._TOKEN_SECRET).encode('ascii'),\n            base_string.encode(), hashlib.sha1).digest()).decode()\n        encoded_query += '&oauth_signature=' + compat_urllib_parse.quote(oauth_signature, '')\n        try:\n            return self._download_json(\n                '?'.join([base_url, encoded_query]), video_id,\n                note='Downloading %s JSON metadata' % note, headers=headers, data=data)\n        except ExtractorError as e:\n            if isinstance(e.cause, compat_HTTPError) and e.cause.code == 401:\n                raise ExtractorError(json.loads(e.cause.read().decode())['message'], expected=True)\n            raise\n\n    def _call_cms(self, path, video_id, note):\n        if not self._CMS_SIGNING:\n            index = self._call_api('index', video_id, 'CMS Signing')\n            self._CMS_SIGNING = index.get('cms_signing') or {}\n            if not self._CMS_SIGNING:\n                for signing_policy in index.get('signing_policies', []):\n                    signing_path = signing_policy.get('path')\n                    if signing_path and signing_path.startswith('/cms/'):\n                        name, value = signing_policy.get('name'), signing_policy.get('value')\n                        if name and value:\n                            self._CMS_SIGNING[name] = value\n        return self._download_json(\n            self._API_DOMAIN + path, video_id, query=self._CMS_SIGNING,\n            note='Downloading %s JSON metadata' % note, headers=self.geo_verification_headers())\n\n    def _get_cms_resource(self, resource_key, video_id):","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/vrv.py#L44-L80","documentation":"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').","triggerScenarios":"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.","commonSituations":"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).","solutions":["Re-authenticate: pass fresh credentials/cookies so a new token secret is derived","Check the parsed message text — 'Invalid token' vs other messages point to different fixes","Ensure requests come from a supported region (VRV is US/Canada) with a sane system clock"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"from youtube_dl.utils import ExtractorError\ntry:\n    ydl.extract_info(url)\nexcept ExtractorError as e:\n    if 'token' in str(e).lower():\n        reauth_vrv()  # obtain fresh token secret\n        ydl.extract_info(url)  # single retry with new credentials","preventionTips":["Refresh VRV auth tokens proactively — they expire","Keep system clock accurate; OAuth signatures break on skew","Read the parsed 401 body message; it names the exact credential problem"],"tags":["vrv","oauth","http-401","auth-token"],"backgroundTag":null,"analyzedSha":"956b8c585591b401a543e409accb163eeaaa1193","analyzedAt":"2026-08-14T18:59:47.863Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}