yt-dlp/yt-dlp · error · ExtractorError
Could not access playlist: {error_code} {message}
Error message
Could not access playlist: {error_code} {message} What it means
The catch-all branch of BilibiliPlaylistIE's initial-state error handling: the playlist page reported a failure code that is not -400 (watchlater login), -403 (private list) or 11010 (deleted). The error surfaces bilibili's numeric trueCode and message verbatim, so the number in the text is the server's own reason and is the key to diagnosis.
Source
Thrown at yt_dlp/extractor/bilibili.py:1793
def _real_extract(self, url):
list_id = self._match_id(url)
bvid = traverse_obj(parse_qs(url), ('bvid', 0))
if not self._yes_playlist(list_id, bvid):
return self.url_result(f'https://www.bilibili.com/video/{bvid}', BiliBiliIE)
webpage = self._download_webpage(url, list_id)
initial_state = self._search_json(r'window\.__INITIAL_STATE__\s*=', webpage, 'initial state', list_id)
error = traverse_obj(initial_state, (('error', 'listError'), all, lambda _, v: v['code'], any))
if error and error['code'] != 200:
error_code = error.get('trueCode')
if error_code == -400 and list_id == 'watchlater':
self.raise_login_required('You need to login to access your watchlater playlist')
elif error_code == -403:
self.raise_login_required('This is a private playlist. You need to login as its owner')
elif error_code == 11010:
raise ExtractorError('Playlist is no longer available', expected=True)
raise ExtractorError(f'Could not access playlist: {error_code} {error.get("message")}')
query = {
'ps': 20,
'with_current': False,
**traverse_obj(initial_state, {
'type': ('playlist', 'type', {int_or_none}),
'biz_id': ('playlist', 'id', {int_or_none}),
'tid': ('tid', {int_or_none}),
'sort_field': ('sortFiled', {int_or_none}),
'desc': ('desc', {bool_or_none}, {str_or_none}, {str.lower}),
}),
}
metadata = {
'id': f'{query["type"]}_{query["biz_id"]}',
**traverse_obj(initial_state, ('mediaListInfo', {
'title': ('title', {str}),
'uploader': ('upper', 'name', {str}),
'uploader_id': ('upper', 'mid', {str_or_none}),View on GitHub (pinned to 81ecd58b13)
Solutions
- Read the numeric code in the message and match it: not-found-family codes mean a bad mlid, permission-family codes mean login is required.
- Pass cookies: yt-dlp --cookies-from-browser firefox <url> (SESSDATA carries the playlist access).
- Open the URL in a browser logged in as the owner/follower to see the real page state.
- Update yt-dlp in case newer builds map this code to a clearer error.
- Retry after a pause if the browser also shows a verification/captcha interlude - it is risk control, not the playlist.
Defensive patterns
Strategy: try-catch
Try / catch
import re
from yt_dlp.utils import DownloadError
try:
extract(url)
except DownloadError as e:
m = re.search(r'Could not access playlist: (-?\d+)', str(e))
if m:
code = int(m.group(1))
if code == -403:
supply_owner_cookies()
else:
log_and_skip(url, code) Prevention
- Pass SESSDATA cookies whenever downloading bilibili playlists to cover private/follower lists.
- Parse the numeric trueCode out of the message to branch (permission vs not-found vs new code).
- Update yt-dlp so newly introduced codes map to precise errors.
When it happens
Trigger: A /medialist/play URL whose initial state carries an unlisted error code: malformed mlid, list visible only to logged-in followers, region restriction, or transient anti-crawler interference with the page itself.
Common situations: No cookies passed for semi-private lists; playlist id mistyped or truncated when copied; bilibili introduced a new error code the extractor does not special-case yet; page served in a degraded variant to datacenter IPs.
Related errors
- Request failed ({status_code}): {message or "Unknown error"}
- Playlist is no longer available
- Failed to retrieve video list for page {page_num}
- Wrong regex for subtitlelangs: {e.pattern}
- file:// URLs are disabled by default in yt-dlp for security
AI-assisted analysis of yt-dlp/yt-dlp@81ecd58b13 (2026-08-22).
Data as JSON: /api/errors/78a6c914b03f127d.
Report an issue: GitHub.