yt-dlp/yt-dlp · error · ExtractorError
Failed to retrieve video list for page {page + 1}
Error message
Failed to retrieve video list for page {page + 1} What it means
Thrown by MurrtubeUserIE._fetch_page (yt_dlp/extractor/murrtube.py:131) while paginating a user's uploads. The GraphQL POST to https://murrtube.net/graphql (operationName 'Media', limit 10, offset page*10) returned HTTP 200 whose 'data' key is null - the standard GraphQL error envelope - so _download_gql returns None and that page of the video list is unusable. The extractor class is even marked _WORKING = False because the site's API keeps drifting.
Source
Thrown at yt_dlp/extractor/murrtube.py:131
def _fetch_page(self, username, user_id, page):
data = self._download_gql(username, {
'operationName': 'Media',
'variables': {
'limit': self._PAGE_SIZE,
'offset': page * self._PAGE_SIZE,
'sort': 'latest',
'userId': user_id,
},
'query': '''\
query Media($q: String, $sort: String, $userId: ID, $offset: Int!, $limit: Int!) {
media(q: $q, sort: $sort, userId: $userId, offset: $offset, limit: $limit) {
id
__typename
}
}'''},
f'Downloading page {page + 1}')
if data is None:
raise ExtractorError(f'Failed to retrieve video list for page {page + 1}')
media = data['media']
for entry in media:
yield self.url_result('murrtube:{}'.format(entry['id']), MurrtubeIE.ie_key())
def _real_extract(self, url):
username = self._match_id(url)
data = self._download_gql(username, {
'operationName': 'User',
'variables': {
'id': username,
},
'query': '''\
query User($id: ID!) {
user(id: $id) {
id
__typenameView on GitHub (pinned to 81ecd58b13)
Solutions
- Update yt-dlp to the latest nightly (python -m pip -U --pre 'yt-dlp[default]'); murrtube is patched often and is currently marked broken
- Reproduce the call: POST the 'Media' query to https://murrtube.net/graphql with the same variables and read the 'errors' array to see the real reason
- Verify the username is a real profile - the 'User' query in _real_extract must return a user id before pagination starts
- Run with --verbose and confirm the age-check step (murrtube.net/accept_age_check) succeeded; clear cookies and retry
- If the API shape changed, report it with the --verbose log to https://github.com/yt-dlp/yt-dlp/issues
Defensive patterns
Strategy: try-catch
Validate before calling
import json, urllib.request
def murrtube_media_page_ok(username, user_id, page):
op = {'operationName': 'Media', 'variables': {'limit': 10, 'offset': page * 10,
'sort': 'latest', 'userId': user_id},
'query': 'query Media($q: String, $sort: String, $userId: ID, $offset: Int!, $limit: Int!) { media(q: $q, sort: $sort, userId: $userId, offset: $offset, limit: $limit) { id __typename } }'}
req = urllib.request.Request('https://murrtube.net/graphql', data=json.dumps(op).encode(),
headers={'Content-Type': 'application/json'})
with urllib.request.urlopen(req) as r:
return json.load(r).get('data') is not None Type guard
def is_graphql_null_data(resp: dict) -> bool:
return resp.get('data') is None Try / catch
from yt_dlp.utils import ExtractorError
try:
info = ydl.extract_info(url, download=False)
except ExtractorError as e:
if 'Failed to retrieve video list' in str(e):
log.warning('murrtube pagination failed (site API drift, extractor is _WORKING=False): %s', e)
else:
raise Prevention
- Check the extractor status before use: MurrtubeUserIE._WORKING is False, so expect breakage and pin a yt-dlp version known to work
- Keep yt-dlp on the nightly channel when using rarely-maintained extractors
- Extract per-video URLs opportunistically so one failed page does not lose already-yielded entries
- Wrap playlist extraction with extract_info(..., process=False) first to cheaply probe whether the site responds
When it happens
Trigger: POST to murrtube.net/graphql with variables {limit: 10, offset: page*10, sort: 'latest', userId: <id>}; the response body is {'errors': [...], 'data': null} instead of containing a 'media' array - invalid userId, WAF/Cloudflare challenge JSON, or a changed schema. Offsets past the end of a user's media can also return null data.
Common situations: Site API schema drift (extractor already flagged broken via _WORKING = False); stale yt-dlp version; missing age-check session because _real_initialize could not set the murrtube.net cookies; datacenter IP served a challenge instead of GraphQL data.
Related errors
- Failed to fetch user info
- Track not found
- Track is restricted
- Support for murrtube: prefix URLs is broken
- No Nintendo Direct with id {slug} exists
AI-assisted analysis of yt-dlp/yt-dlp@81ecd58b13 (2026-08-22).
Data as JSON: /api/errors/73f004e050ea9c4c.
Report an issue: GitHub.