ytdl-org/youtube-dl · error · ExtractorError
%s said: %s
Error message
%s said: %s
What it means
Raised by the mojvideo.com extractor when the playerapi.php XML response contains '<error>true</error>'. The extractor then scrapes <errordesc> for the human-readable reason and re-raises it prefixed with the extractor name. Expected=True — a faithful relay of the site's own error channel.
Source
Thrown at youtube_dl/extractor/mojvideo.py:40
'title': 'V avtu pred mano rdečelaska - Alfi Nipič',
'thumbnail': r're:^http://.*\.jpg$',
'duration': 242,
}
}
def _real_extract(self, url):
mobj = re.match(self._VALID_URL, url)
video_id = mobj.group('id')
display_id = mobj.group('display_id')
# XML is malformed
playerapi = self._download_webpage(
'http://www.mojvideo.com/playerapi.php?v=%s&t=1' % video_id, display_id)
if '<error>true</error>' in playerapi:
error_desc = self._html_search_regex(
r'<errordesc>([^<]*)</errordesc>', playerapi, 'error description', fatal=False)
raise ExtractorError('%s said: %s' % (self.IE_NAME, error_desc), expected=True)
title = self._html_search_regex(
r'<title>([^<]+)</title>', playerapi, 'title')
video_url = self._html_search_regex(
r'<file>([^<]+)</file>', playerapi, 'video URL')
thumbnail = self._html_search_regex(
r'<preview>([^<]+)</preview>', playerapi, 'thumbnail', fatal=False)
duration = parse_duration(self._html_search_regex(
r'<duration>([^<]+)</duration>', playerapi, 'duration', fatal=False))
return {
'id': video_id,
'display_id': display_id,
'url': video_url,
'title': title,
'thumbnail': thumbnail,
'duration': duration,
}View on GitHub (pinned to 956b8c5855)
Solutions
- Read the errordesc text — it is mojvideo's stated reason.
- Verify the video at www.mojvideo.com in a browser.
- If the whole service is offline/erroring, source the media elsewhere; no client fix recovers it.
Defensive patterns
Strategy: try-catch
Type guard
def mojvideo_api_error(api_xml):
return isinstance(api_xml, str) and '<error>true</error>' in api_xml Try / catch
try:
info = ydl.extract_info(url, download=False)
except ExtractorError as e:
if 'mojvideo said:' in str(e):
mark_permanently_dead(url) # site's API declared the video gone
else:
raise Prevention
- Verify mojvideo ids in a browser before queueing (service is largely defunct).
- Treat '<error>true</error>' responses as permanent; do not retry.
When it happens
Trigger: GET http://www.mojvideo.com/playerapi.php?v={id}&t=1 returns malformed XML containing <error>true</error>; <errordesc> is searched with fatal=False, so a missing errordesc yields None and the message reads 'mojvideo said: None'.
Common situations: Video deleted from mojvideo; private/pending-approval videos; the Slovenian service (largely defunct) returning errors for all ids; API changes renaming errordesc.
Related errors
- %s encountered an error: %s
- %s said: %s
- Unable to login: %s
- lynda returned error: %s
- Course %s does not exist
AI-assisted analysis of ytdl-org/youtube-dl@956b8c5855 (2026-08-14).
Data as JSON: /api/errors/4dc6edc6ec977f21.
Report an issue: GitHub.