ytdl-org/youtube-dl · error · ExtractorError

%s: %s

Error message

%s: %s

What it means

This is the generic failure template of _download_webpage internals: when a webpage (or API) download raises a network/HTTP error that is not handled more specifically, youtube-dl builds '<errnote>: <original error>' and, if fatal=True, raises ExtractorError with the underlying exception as cause. 'errnote' defaults to 'Unable to download webpage' but extractors override it (e.g. 'Unable to download API JSON').

Source

Thrown at youtube_dl/extractor/common.py:700

            return self._downloader.urlopen(url_or_request)
        except tuple(exceptions) as err:
            if isinstance(err, compat_urllib_error.HTTPError):
                if self.__can_accept_status_code(err, expected_status):
                    # Retain reference to error to prevent file object from
                    # being closed before it can be read. Works around the
                    # effects of <https://bugs.python.org/issue15002>
                    # introduced in Python 3.4.1.
                    err.fp._error = err
                    return err.fp

            if errnote is False:
                return False
            if errnote is None:
                errnote = 'Unable to download webpage'

            errmsg = '%s: %s' % (errnote, error_to_compat_str(err))
            if fatal:
                raise ExtractorError(errmsg, sys.exc_info()[2], cause=err)
            else:
                self.report_warning(errmsg)
                return False

    def _download_webpage_handle(self, url_or_request, video_id, note=None, errnote=None, fatal=True, encoding=None, data=None, headers={}, query={}, expected_status=None):
        """
        Return a tuple (page content as string, URL handle).

        See _download_webpage docstring for arguments specification.
        """
        # Strip hashes from the URL (#1038)
        if isinstance(url_or_request, (compat_str, str)):
            url_or_request = url_or_request.partition('#')[0]

        urlh = self._request_webpage(url_or_request, video_id, note, errnote, fatal, data=data, headers=headers, query=query, expected_status=expected_status)
        if urlh is False:
            assert not fatal
            return False

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Read the '<original error>' part of the message — it names the real cause (HTTP Error 404, connection reset, etc.).
  2. Set a browser-like User-Agent (--user-agent) and/or pass cookies (--cookies) to pass bot checks.
  3. Check the URL in a browser; 404s mean the link is dead.
  4. For flaky networks, increase --retries/--socket-timeout or use --force-ipv4.

Example fix

# before
ydl.extract(url)  # ERROR: Unable to download webpage: HTTP Error 403: Forbidden

# after
from youtube_dl import YoutubeDL
with YoutubeDL({'http_headers': {'User-Agent': 'Mozilla/5.0'}}) as ydl:
    ydl.extract(url)
Defensive patterns

Strategy: try-catch

Validate before calling

import urllib.request
def url_reachable(url, headers):
    try:
        req = urllib.request.Request(url, headers=headers)
        with urllib.request.urlopen(req, timeout=15) as r:
            return r.status == 200
    except Exception:
        return False

Try / catch

from youtube_dl.utils import ExtractorError, DownloadError
try:
    ydl.extract_info(url)
except ExtractorError as e:
    msg = str(e)
    if 'HTTP Error 403' in msg:
        retry_with_browser_ua(url)      # bot block
    elif 'HTTP Error 404' in msg:
        mark_dead(url)                   # permanent
    else:
        raise

Prevention

When it happens

Trigger: Any URLError/HTTPError/socket failure while fetching a URL the extractor requested: DNS failure, connection refused, TLS errors, 403/404/500 responses (unless expected_status was set), timeouts. fatal=False converts it to a warning and returns False instead.

Common situations: Dead links (404), bot-blocking WAFs returning 403 to youtube-dl's default User-Agent, corporate proxies/DNS issues, TLS interception problems, transient 5xx.

Related errors


AI-assisted analysis of ytdl-org/youtube-dl@956b8c5855 (2026-08-14). Data as JSON: /api/errors/9d50c4426ad09782. Report an issue: GitHub.