ytdl-org/youtube-dl · warning · ExtractorError

Invalid URL: %r . Call youtube-dl like this: youtube-dl -v

Error message

Invalid URL:  %r . Call youtube-dl like this:  youtube-dl -v "https://www.youtube.com/watch?v=BaW_jenozKc"  

What it means

Raised by the generic extractor when the URL has no scheme, default_search is 'auto_warning', and the input is literally 'url' or 'URL'. youtube-dl interprets a bare 'url' as a likely mistyped placeholder and refuses to fall back to a YouTube search for it. Marked expected=True.

Source

Thrown at youtube_dl/extractor/generic.py:2546

    def _real_extract(self, url):
        if url.startswith('//'):
            return self.url_result(self.http_scheme() + url)

        parsed_url = compat_urlparse.urlparse(url)
        if not parsed_url.scheme:
            default_search = self._downloader.params.get('default_search')
            if default_search is None:
                default_search = 'fixup_error'

            if default_search in ('auto', 'auto_warning', 'fixup_error'):
                if re.match(r'^[^\s/]+\.[^\s/]+/', url):
                    self._downloader.report_warning('The url doesn\'t specify the protocol, trying with http')
                    return self.url_result('http://' + url)
                elif default_search != 'fixup_error':
                    if default_search == 'auto_warning':
                        if re.match(r'^(?:url|URL)$', url):
                            raise ExtractorError(
                                'Invalid URL:  %r . Call youtube-dl like this:  youtube-dl -v "https://www.youtube.com/watch?v=BaW_jenozKc"  ' % url,
                                expected=True)
                        else:
                            self._downloader.report_warning(
                                'Falling back to youtube search for  %s . Set --default-search "auto" to suppress this warning.' % url)
                    return self.url_result('ytsearch:' + url)

            if default_search in ('error', 'fixup_error'):
                raise ExtractorError(
                    '%r is not a valid URL. '
                    'Set --default-search "ytsearch" (or run  youtube-dl "ytsearch:%s" ) to search YouTube'
                    % (url, url), expected=True)
            else:
                if ':' not in default_search:
                    default_search += ':'
                return self.url_result(default_search + url)

        url, smuggled_data = unsmuggle_url(url)

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Pass a real URL including the scheme: youtube-dl "https://www.youtube.com/watch?v=BaW_jenozKc"
  2. Fix the script/variable that substituted the literal string 'url'
  3. Set --default-search explicitly if you really want search behavior

Example fix

# before
youtube-dl url
# after
youtube-dl "https://www.youtube.com/watch?v=BaW_jenozKc"
Defensive patterns

Strategy: validation

Validate before calling

import re
def valid_cli_url(u):
    return bool(re.match(r'^[a-zA-Z][a-zA-Z0-9+.-]*://', u)) or bool(re.match(r'^[^\s/]+\.[^\s/]+/', u))
if not valid_cli_url(arg) or arg.lower() in ('url',):
    raise SystemExit(f'not a real URL: {arg!r}')

Type guard

def is_placeholder_url(u):
    return u.strip().lower() in ('url', 'http://url', 'https://url')

Try / catch

try:
    ydl.download([arg])
except DownloadError:
    # expected=True error; correct the argument, no need to log as a bug
    print('pass a full URL, not the literal placeholder "url"')

Prevention

When it happens

Trigger: Invoking the CLI with the literal argument url or URL (e.g. youtube-dl $(cat cmd.txt) where the file contained the word 'url') while --default-search is auto_warning, and the input matches neither the domain regex ^[^\s/]+\.[^\s/]+/ nor a scheme.

Common situations: Shell scripts templating a URL variable that expanded to the placeholder 'url', copy-paste of an example command without substitution, or CI configs passing an unset variable defaulting to 'url'.

Related errors


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