{"record":{"id":"77731f8fa0826de5","repo":"ytdl-org/youtube-dl","slug":"s-said-s-77731f","errorCode":null,"errorMessage":"%s said: %s","messagePattern":"%s said: %s","errorType":"exception","errorClass":"ExtractorError","httpStatus":null,"severity":"error","filePath":"youtube_dl/extractor/rtbf.py","lineNumber":80,"sourceCode":"        'VIMEO': 'Vimeo',\n    }\n    _QUALITIES = [\n        ('mobile', 'SD'),\n        ('web', 'MD'),\n        ('high', 'HD'),\n    ]\n\n    def _real_extract(self, url):\n        live, media_id = re.match(self._VALID_URL, url).groups()\n        embed_page = self._download_webpage(\n            'https://www.rtbf.be/auvio/embed/' + ('direct' if live else 'media'),\n            media_id, query={'id': media_id})\n        data = self._parse_json(self._html_search_regex(\n            r'data-media=\"([^\"]+)\"', embed_page, 'media data'), media_id)\n\n        error = data.get('error')\n        if error:\n            raise ExtractorError('%s said: %s' % (self.IE_NAME, error), expected=True)\n\n        provider = data.get('provider')\n        if provider in self._PROVIDERS:\n            return self.url_result(data['url'], self._PROVIDERS[provider])\n\n        title = data['title']\n        is_live = data.get('isLive')\n        if is_live:\n            title = self._live_title(title)\n        height_re = r'-(\\d+)p\\.'\n        formats = []\n\n        m3u8_url = data.get('urlHlsAes128') or data.get('urlHls')\n        if m3u8_url:\n            formats.extend(self._extract_m3u8_formats(\n                m3u8_url, media_id, 'mp4', m3u8_id='hls', fatal=False))\n\n        fix_url = lambda x: x.replace('//rtbf-vod.', '//rtbf.') if '/geo/drm/' in x else x","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/rtbf.py#L62-L98","documentation":"Raised by the RTBF (Belgian broadcaster) auvio extractor when the JSON embedded in the embed page's data-media attribute contains a non-empty 'error' key. The message is 'RTBF said: <error text as returned by the site>'. Expected=True - the site itself reported the failure.","triggerScenarios":"Extracting any rtbf.be/auvio/(media|direct)/<id> URL whose embed endpoint returns JSON with an 'error' field: geo-blocked content, removed media, expired live streams, or invalid ids.","commonSituations":"Requesting RTBF content from outside Belgium (geo-restriction), catching a live stream after it ended, or following dead links.","solutions":["Read the interpolated error text from RTBF - it names the exact cause (geo-block, removed, etc.).","If geo-blocked, no client-side fix exists beyond accessing it from an allowed region.","Verify the media id / URL is still valid on rtbf.be.","If the page plays fine in a browser, the data-media JSON moved - update youtube-dl."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    ydl.extract_info(url)\nexcept ExtractorError as e:\n    if str(e).startswith('RTBF said:'):\n        log_site_error(url, str(e))  # message names geo-block/expired/invalid\n    else:\n        raise","preventionTips":["Log the site-provided text verbatim - it distinguishes geo-blocks from dead ids.","For live streams (direct/ URLs), extract during broadcast windows only.","Remember no credential or retry fixes a geo-block."],"tags":["rtbf","geo-restriction","site-error","expected-error"],"backgroundTag":null,"analyzedSha":"956b8c585591b401a543e409accb163eeaaa1193","analyzedAt":"2026-08-14T18:59:47.863Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}