yt-dlp/yt-dlp · error · ExtractorError
Failed to get m3u8 playlist
Error message
Failed to get m3u8 playlist
What it means
Raised by TwitCastingIE when the movie playlist yields no m3u8 URLs and the websocket-fragment path produced no formats either (that path raises a login error first when empty). It means no playable HLS manifest could be located for the movie, typically because the stream data is not exposed anonymously. Raised without expected=True, so it is treated as an extraction failure.
Source
Thrown at yt_dlp/extractor/twitcasting.py:218
formats.append({
'url': update_url_query(ws_url, password_params),
'format_id': f'ws-{mode}',
'ext': 'mp4',
'quality': qq(mode),
'source_preference': -10,
# TwitCasting simply sends moof atom directly over WS
'protocol': 'websocket_frag',
})
if not formats:
self.raise_login_required()
infodict = {
'formats': formats,
'_format_sort_fields': ('source', ),
}
elif not m3u8_urls:
raise ExtractorError('Failed to get m3u8 playlist')
elif len(m3u8_urls) == 1:
formats = self._extract_m3u8_formats(
m3u8_urls[0], video_id, 'mp4', headers=self._M3U8_HEADERS)
infodict = {
# No problem here since there's only one manifest
'formats': formats,
'http_headers': self._M3U8_HEADERS,
}
else:
infodict = {
'_type': 'multi_video',
'entries': [{
'id': f'{video_id}-{num}',
'url': m3u8_url,
'ext': 'mp4',
# Requesting the manifests here will cause download to fail.
# So use ffmpeg instead. See: https://github.com/yt-dlp/yt-dlp/issues/382
'protocol': 'm3u8',View on GitHub (pinned to 81ecd58b13)
Solutions
- If the stream is members-only, log in via --username/--password or --cookies and retry.
- Confirm the movie page shows a playable recording in a browser.
- Update yt-dlp; playlist parsing was adjusted several times after TwitCasting markup changes.
- For recent recordings, retry once processing finishes.
Defensive patterns
Strategy: try-catch
Type guard
def is_login_or_no_formats(e: Exception) -> bool:
return isinstance(e, LoginRequired) or (isinstance(e, ExtractorError) and 'm3u8 playlist' in str(e)) Try / catch
from yt_dlp.utils import ExtractorError, LoginRequired
try:
info = ydl.extract_info(url, download=False)
except LoginRequired:
... # websocket path found nothing; members-only content
except ExtractorError as e:
if 'Failed to get m3u8 playlist' in str(e):
... # no anonymous HLS; retry with credentials or skip Prevention
- Use --cookies-from-browser for members-only TwitCasting recordings.
- Retry recent recordings later; HLS appears once processing finishes.
- Update yt-dlp after TwitCasting markup changes.
When it happens
Trigger: data-movie-playlist JSON contains no HLS bitrates (empty m3u8_urls) and the WebSocket pass yields nothing because the video is members-only or the playlist shape changed, falling into the 'elif not m3u8_urls' branch.
Common situations: Members-only (paid community) streams without login, deleted videos whose playlist is emptied, recordings still processing, or a TwitCasting markup change that hides the playlist attribute.
Related errors
- No downloads available
- This video is unplayable
- Found song but don't know how to download it
- This video is protected by a password, use the --video-passw
- The channel is not currently live
AI-assisted analysis of yt-dlp/yt-dlp@81ecd58b13 (2026-08-22).
Data as JSON: /api/errors/5b17e3a33955b026.
Report an issue: GitHub.