ytdl-org/youtube-dl · warning · ExtractorError
error
Error message
error
What it means
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.
Source
Thrown at youtube_dl/extractor/chaturbate.py:84
m3u8_urls = []
for found_m3u8_url in found_m3u8_urls:
m3u8_fast_url, m3u8_no_fast_url = found_m3u8_url, found_m3u8_url.replace('_fast', '')
for m3u8_url in (m3u8_fast_url, m3u8_no_fast_url):
if m3u8_url not in m3u8_urls:
m3u8_urls.append(m3u8_url)
if not m3u8_urls:
error = self._search_regex(
[r'<span[^>]+class=(["\'])desc_span\1[^>]*>(?P<error>[^<]+)</span>',
r'<div[^>]+id=(["\'])defchat\1[^>]*>\s*<p><strong>(?P<error>[^<]+)<'],
webpage, 'error', group='error', default=None)
if not error:
if any(p in webpage for p in (
self._ROOM_OFFLINE, 'offline_tipping', 'tip_offline')):
error = self._ROOM_OFFLINE
if error:
raise ExtractorError(error, expected=True)
raise ExtractorError('Unable to find stream URL')
formats = []
for m3u8_url in m3u8_urls:
for known_id in ('fast', 'slow'):
if '_%s' % known_id in m3u8_url:
m3u8_id = known_id
break
else:
m3u8_id = None
formats.extend(self._extract_m3u8_formats(
m3u8_url, video_id, ext='mp4',
# ffmpeg skips segments for fast m3u8
preference=-10 if m3u8_id == 'fast' else None,
m3u8_id=m3u8_id, fatal=False, live=True))
self._sort_formats(formats)
return {View on GitHub (pinned to 956b8c5855)
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.
Example fix
import time
from youtube_dl.utils import ExtractorError
while True:
try:
ydl.extract(room_url, download=True)
break
except ExtractorError as e:
if 'offline' in str(e).lower():
time.sleep(60) # wait for the room to go live
else:
raise Defensive patterns
Strategy: retry
Validate before calling
# pre-flight: is the room live?
html = http_get(room_url)
if 'ROOM IS CURRENTLY OFFLINE' in html or 'offline_tipping' in html:
schedule_retry_later(room_url) Try / catch
from youtube_dl.utils import ExtractorError
try:
ydl.extract_info(room_url)
except ExtractorError as e:
msg = str(e).lower()
if 'offline' in msg or 'away' in msg:
sleep_and_requeue(room_url, 60) # transient: room not broadcasting
else:
raise # e.g. private/banned: permanent Prevention
- 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.
When it happens
Trigger: 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.)
Common situations: 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.
Related errors
- This user is offline.
- Stream is offline
- %s is offline
- This live stream has already finished.
- this video has been %s
AI-assisted analysis of ytdl-org/youtube-dl@956b8c5855 (2026-08-14).
Data as JSON: /api/errors/58370f7c412d7cd1.
Report an issue: GitHub.