{"record":{"id":"e32ac0b8b7a2bce7","repo":"yt-dlp/yt-dlp","slug":"code-error-id-message","errorCode":null,"errorMessage":"{code}: {error_id}: {message}","messagePattern":"\\{code\\}: \\{error_id\\}: \\{message\\}","errorType":"exception","errorClass":"ExtractorError","httpStatus":null,"severity":"error","filePath":"yt_dlp/extractor/streaks.py","lineNumber":56,"sourceCode":"\n    def _extract_from_streaks_api(self, project_id, media_id, headers=None, query=None, live_from_start=False):\n        try:\n            response = self._download_streaks_playback_json(project_id, media_id, headers=headers)\n        except ExtractorError as e:\n            if isinstance(e.cause, HTTPError) and e.cause.status in (403, 404):\n                error = self._parse_json(e.cause.response.read().decode(), media_id, fatal=False)\n                message = traverse_obj(error, ('message', {clean_html}, filter))\n                code = traverse_obj(error, ('code', {clean_html}, filter))\n                error_id = traverse_obj(error, ('id', {int_or_none}))\n                if code == 'REQUEST_FAILED':\n                    if error_id == 124:\n                        self.raise_geo_restricted(countries=self._GEO_COUNTRIES)\n                    elif error_id == 126:\n                        raise ExtractorError('Access is denied (possibly due to invalid/missing API key)')\n                if code == 'MEDIA_NOT_FOUND':\n                    raise ExtractorError(join_nonempty(code, message, delim=': '), expected=True)\n                if code or message:\n                    raise ExtractorError(join_nonempty(code, error_id, message, delim=': '))\n            raise\n\n        streaks_id = response['id']\n        live_status = {\n            'clip': 'was_live',\n            'file': 'not_live',\n            'linear': 'is_live',\n            'live': 'is_live',\n        }.get(response.get('type'))\n\n        formats, subtitles = [], {}\n        drm_formats = False\n        sources = response['sources']\n        ssai = traverse_obj(sources, (..., 'ssai', {dict}, any))\n\n        for source in traverse_obj(sources, (\n            lambda _, v: url_or_none(v['src']),\n        )):","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/yt-dlp/yt-dlp/blob/81ecd58b1394793e6da9998cc19fdb45657f1685/yt_dlp/extractor/streaks.py#L38-L74","documentation":"Thrown by StreaksBaseIE as a catch-all for STREAKS API errors: HTTP 403/404 whose JSON body carries any 'code' or 'message' other than the special-cased REQUEST_FAILED(124/126) and MEDIA_NOT_FOUND. The message is built with join_nonempty(code, error_id, message), so it reads like 'RATE_LIMITED: 77: too many requests'. Not marked expected, so yt-dlp treats it as an extraction failure.","triggerScenarios":"The playback API returns an unmapped error code — rate limiting, expired token, bad request, project suspended — with 403/404 status and a JSON body containing 'code' and/or 'message'. Anything not matching the two special cases funnels here.","commonSituations":"Hammering the API from one IP triggers throttling codes; site adds a new error code the extractor has not mapped; entitlement/token codes when the media requires auth the caller did not send.","solutions":["Re-run with yt_dlp -v to see the full message; the embedded code/id/message identifies the backend reason.","If it looks like throttling, wait and retry with slower rate (--limit-rate, sleep_interval) or fewer parallel fragment downloads.","Update yt-dlp to latest — new codes get mapped to friendlier errors over time.","If the message indicates auth/entitlement, supply cookies (--cookies-from-browser) or view the page in a browser to see what access it demands."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"from yt_dlp.utils import ExtractorError\nfor attempt in range(3):\n    try:\n        ydl.extract_info(url)\n        break\n    except ExtractorError as e:\n        if 'RATE_LIMIT' in str(e).upper():\n            time.sleep(30 * (attempt + 1))\n            continue\n        raise","preventionTips":["Rate-limit your own requests to the streaks API (sleep between items).","Log the raw code/error_id passthrough — it identifies the true backend reason.","Update yt-dlp so newly mapped codes surface friendlier errors."],"tags":["yt-dlp","extractor","streaks","api-error","passthrough-error"],"backgroundTag":"api-error-response","analyzedSha":"81ecd58b1394793e6da9998cc19fdb45657f1685","analyzedAt":"2026-08-22T12:21:25.439Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}