{"record":{"id":"58370f7c412d7cd1","repo":"ytdl-org/youtube-dl","slug":"error-58370f","errorCode":null,"errorMessage":"error","messagePattern":"error","errorType":"exception","errorClass":"ExtractorError","httpStatus":null,"severity":"warning","filePath":"youtube_dl/extractor/chaturbate.py","lineNumber":84,"sourceCode":"\n        m3u8_urls = []\n        for found_m3u8_url in found_m3u8_urls:\n            m3u8_fast_url, m3u8_no_fast_url = found_m3u8_url, found_m3u8_url.replace('_fast', '')\n            for m3u8_url in (m3u8_fast_url, m3u8_no_fast_url):\n                if m3u8_url not in m3u8_urls:\n                    m3u8_urls.append(m3u8_url)\n\n        if not m3u8_urls:\n            error = self._search_regex(\n                [r'<span[^>]+class=([\"\\'])desc_span\\1[^>]*>(?P<error>[^<]+)</span>',\n                 r'<div[^>]+id=([\"\\'])defchat\\1[^>]*>\\s*<p><strong>(?P<error>[^<]+)<'],\n                webpage, 'error', group='error', default=None)\n            if not error:\n                if any(p in webpage for p in (\n                        self._ROOM_OFFLINE, 'offline_tipping', 'tip_offline')):\n                    error = self._ROOM_OFFLINE\n            if error:\n                raise ExtractorError(error, expected=True)\n            raise ExtractorError('Unable to find stream URL')\n\n        formats = []\n        for m3u8_url in m3u8_urls:\n            for known_id in ('fast', 'slow'):\n                if '_%s' % known_id in m3u8_url:\n                    m3u8_id = known_id\n                    break\n            else:\n                m3u8_id = None\n            formats.extend(self._extract_m3u8_formats(\n                m3u8_url, video_id, ext='mp4',\n                # ffmpeg skips segments for fast m3u8\n                preference=-10 if m3u8_id == 'fast' else None,\n                m3u8_id=m3u8_id, fatal=False, live=True))\n        self._sort_formats(formats)\n\n        return {","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/chaturbate.py#L66-L102","documentation":"Raised by ChaturbateIE when no m3u8 playlist URLs were found on the room page. The extractor first scrapes an error text from known markup (a .desc_span span or the #defchat <strong> line); if that matches, the room's own status message (often ROOM IS CURRENTLY OFFLINE) is raised as an expected ExtractorError.","triggerScenarios":"The room page contains no playlist (m3u8_urls empty) plus one of the error markers — room offline, hidden/private, or banned — OR the page contains 'offline_tipping'/'tip_offline' strings which are mapped to the offline message. (If NO error marker is found, a different 'Unable to find stream URL' error is raised instead.)","commonSituations":"Trying to record a room that is not currently broadcasting; private/password-protected shows; the model's page markup changed so the regexes no longer capture the status text.","solutions":["Only extract while the room is actually streaming; poll the room URL and retry when it becomes live.","For password rooms, pass the room password mechanism if supported (or an authenticated session cookie).","If the page clearly shows a stream but you still get an error text, update to yt-dlp — the markup regexes are brittle.","Treat the error string literally: it is copied from the room's own status line."],"exampleFix":"import time\nfrom youtube_dl.utils import ExtractorError\n\nwhile True:\n    try:\n        ydl.extract(room_url, download=True)\n        break\n    except ExtractorError as e:\n        if 'offline' in str(e).lower():\n            time.sleep(60)  # wait for the room to go live\n        else:\n            raise","handlingStrategy":"retry","validationCode":"# pre-flight: is the room live?\nhtml = http_get(room_url)\nif 'ROOM IS CURRENTLY OFFLINE' in html or 'offline_tipping' in html:\n    schedule_retry_later(room_url)","typeGuard":null,"tryCatchPattern":"from youtube_dl.utils import ExtractorError\ntry:\n    ydl.extract_info(room_url)\nexcept ExtractorError as e:\n    msg = str(e).lower()\n    if 'offline' in msg or 'away' in msg:\n        sleep_and_requeue(room_url, 60)   # transient: room not broadcasting\n    else:\n        raise                              # e.g. private/banned: permanent","preventionTips":["Poll room state before starting a recording job.","Classify offline/private messages as transient vs permanent.","Start recording jobs only once the m3u8 appears in the page."],"tags":["chaturbate","offline","live-stream","regex"],"backgroundTag":null,"analyzedSha":"956b8c585591b401a543e409accb163eeaaa1193","analyzedAt":"2026-08-14T18:59:47.863Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}