ytdl-org/youtube-dl · error · ExtractorError

Invalid URL: %s

Error message

Invalid URL: %s

What it means

Raised by the static YoutubeIE.extract_id when the given URL does not match the (verbose) _VALID_URL regex for YouTube video URLs. It is a plain ExtractorError (not expected), signaling the caller passed something that is not a recognizable youtube.com/watch (or equivalent) URL — typically a truncated URL mangled by the shell.

Source

Thrown at youtube_dl/extractor/youtube.py:2254

        # Wordpress "YouTube Video Importer" plugin
        matches = re.findall(r'''(?x)<div[^>]+
            class=(?P<q1>[\'"])[^\'"]*\byvii_single_video_player\b[^\'"]*(?P=q1)[^>]+
            data-video_id=(?P<q2>[\'"])([^\'"]+)(?P=q2)''', webpage)
        entries.extend(m[-1] for m in matches)

        return entries

    @staticmethod
    def _extract_url(webpage):
        urls = YoutubeIE._extract_urls(webpage)
        return urls[0] if urls else None

    @classmethod
    def extract_id(cls, url):
        mobj = re.match(cls._VALID_URL, url, re.VERBOSE)
        if mobj is None:
            raise ExtractorError('Invalid URL: %s' % url)
        return mobj.group(2)

    @staticmethod
    def _extract_chapters_from_json(data, video_id, duration):
        chapters_list = try_get(
            data,
            lambda x: x['playerOverlays']
                       ['playerOverlayRenderer']
                       ['decoratedPlayerBarRenderer']
                       ['decoratedPlayerBarRenderer']
                       ['playerBar']
                       ['chapteredPlayerBarRenderer']
                       ['chapters'],
            list)
        if not chapters_list:
            return

        def chapter_time(chapter):

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Quote the URL: youtube-dl "https://www.youtube.com/watch?feature=foo&v=BaW_jenozKc", or pass just the id: youtube-dl BaW_jenozKc.
  2. In code, validate with YoutubeIE.suitable(url) (or re.match(_VALID_URL, url, re.VERBOSE)) before calling extract_id.
  3. Update youtube-dl so newly added YouTube hosts/URL shapes are recognized.
  4. Check for stray whitespace/newlines in programmatically supplied URLs.

Example fix

// before
video_id = YoutubeIE.extract_id('https://www.youtube.com/watch?feature=foo')

// after
video_id = YoutubeIE.extract_id('https://www.youtube.com/watch?feature=foo&v=BaW_jenozKc')  # quoted in shell: "...&v=BaW_jenozKc"
Defensive patterns

Strategy: validation

Validate before calling

import re

def is_valid_youtube_url(url: str) -> bool:
    return re.match(YoutubeIE._VALID_URL, url, re.VERBOSE) is not None

assert is_valid_youtube_url(url), 'URL lacks the video id (quote it in shells!)'

Type guard

def extract_video_id_safe(url: str):
    m = re.match(YoutubeIE._VALID_URL, url, re.VERBOSE)
    return m.group(2) if m else None  # None instead of raising

Try / catch

try:
    vid = YoutubeIE.extract_id(url)
except ExtractorError as e:
    if 'Invalid URL' in str(e):
        raise ValueError('Not a YouTube video URL: %r — was it truncated at & ?' % url)
    raise

Prevention

When it happens

Trigger: Calling YoutubeIE.extract_id('https://www.youtube.com/watch?feature=foo') — an URL whose query string was cut at '&' by an unquoted shell — or any string that does not contain a capturable 11-char video id group.

Common situations: Unquoted URLs in shells where & backgrounds the command and truncates the URL; programmatic callers passing already-stripped or malformed URLs; URLs from other regions/hosts not covered by _VALID_URL in the installed version.

Related errors


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