ytdl-org/youtube-dl · error · ExtractorError
PornHub said: %s
Error message
PornHub said: %s
What it means
PornHubIE._real_extract raises ExtractorError('PornHub said: %s' % error_msg, expected=True) right after downloading the PC webpage, when the HTML contains an error block matched by either the 'removed|userMessageSection' div regex or the 'noVideo' section regex. The scraped block text (whitespace-collapsed) is appended, so the message is the site's own removal/unavailability notice.
Source
Thrown at youtube_dl/extractor/pornhub.py:284
self._login(host)
self._set_cookie(host, 'age_verified', '1')
def dl_webpage(platform):
self._set_cookie(host, 'platform', platform)
return self._download_webpage(
'https://www.%s/view_video.php?viewkey=%s' % (host, video_id),
video_id, 'Downloading %s webpage' % platform)
webpage = dl_webpage('pc')
error_msg = self._html_search_regex(
(r'(?s)<div[^>]+class=(["\'])(?:(?!\1).)*\b(?:removed|userMessageSection)\b(?:(?!\1).)*\1[^>]*>(?P<error>.+?)</div>',
r'(?s)<section[^>]+class=["\']noVideo["\'][^>]*>(?P<error>.+?)</section>'),
webpage, 'error message', default=None, group='error')
if error_msg:
error_msg = re.sub(r'\s+', ' ', error_msg)
raise ExtractorError(
'PornHub said: %s' % error_msg,
expected=True, video_id=video_id)
if any(re.search(p, webpage) for p in (
r'class=["\']geoBlocked["\']',
r'>\s*This content is unavailable in your country')):
self.raise_geo_restricted()
# video_title from flashvars contains whitespace instead of non-ASCII (see
# http://www.pornhub.com/view_video.php?viewkey=1331683002), not relying
# on that anymore.
title = self._html_search_meta(
'twitter:title', webpage, default=None) or self._html_search_regex(
(r'(?s)<h1[^>]+class=["\']title["\'][^>]*>(?P<title>.+?)</h1>',
r'<div[^>]+data-video-title=(["\'])(?P<title>(?:(?!\1).)+)\1',
r'shareTitle["\']\s*[=:]\s*(["\'])(?P<title>(?:(?!\1).)+)\1'),
webpage, 'title', group='title')
View on GitHub (pinned to 956b8c5855)
Solutions
- Read the trailing site message in the error — it states whether the video was removed or is otherwise unavailable.
- Drop the dead URL from the batch and continue with remaining entries.
- Confirm in a browser that the video still exists; if the browser shows it fine, update youtube-dl (markup drift can false-positive this regex).
- If the page says deleted/removed, no client-side fix exists — obtain a re-uploaded or canonical URL.
Defensive patterns
Strategy: try-catch
Try / catch
try:
info = ydl.extract_info(url)
except ExtractorError as e:
if 'PornHub said:' in str(e):
mark_dead(url) # removed/private; skip permanently Prevention
- Classify 'PornHub said:' errors as permanent URL failures in job runners.
- Distinguish this from geo-restriction (different exception path) before choosing a fix.
- Re-validate stored PornHub links occasionally to purge takedowns.
When it happens
Trigger: Extracting a video that was removed (removed div), deleted by its uploader, made private, or blocked, where the page renders a userMessageSection/noVideo block instead of the player; checked before geo-blocking detection, so plain removal hits this branch first.
Common situations: Stale links in saved playlists pointing to taken-down videos; DMCA removals; uploader-deleted content; age/verification gating that renders the same error section. Distinct from geo-blocking, which is detected just after this check and raises raise_geo_restricted instead.
Related errors
- %s said: %s
- Video %s is locked
- %s says: %s (IE_NAME, msg) or 'Video unavailable: no reason
- Unable to login: %s
- %s said: %s
AI-assisted analysis of ytdl-org/youtube-dl@956b8c5855 (2026-08-14).
Data as JSON: /api/errors/d45728cf84f23ceb.
Report an issue: GitHub.