ytdl-org/youtube-dl · warning · ExtractorError
%r is not a valid URL. Set --default-search "ytsearch" (or r
Error message
%r is not a valid URL. Set --default-search "ytsearch" (or run youtube-dl "ytsearch:%s" ) to search YouTube
What it means
Raised by the generic extractor when the URL has no scheme, the input does not look like a bare domain (fails ^[^\s/]+\.[^\s/]+/), and default_search is 'error' or the default 'fixup_error'. It tells the user to either supply a full URL or opt into YouTube search. Marked expected=True.
Source
Thrown at youtube_dl/extractor/generic.py:2555
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)
force_videoid = None
is_intentional = smuggled_data and smuggled_data.get('to_generic')
if smuggled_data and 'force_videoid' in smuggled_data:
force_videoid = smuggled_data['force_videoid']
video_id = force_videoid
else:
video_id = self._generic_id(url)
self.to_screen('%s: Requesting header' % video_id)View on GitHub (pinned to 956b8c5855)
Solutions
- Supply the full URL with scheme: youtube-dl "https://www.youtube.com/watch?v=BaW_jenozKc"
- Or enable search: youtube-dl --default-search ytsearch BaW_jenozKc
- Or use the ytsearch prefix directly: youtube-dl "ytsearch:BaW_jenozKc"
Example fix
# before youtube-dl BaW_jenozKc # after youtube-dl "ytsearch:BaW_jenozKc" # or youtube-dl "https://www.youtube.com/watch?v=BaW_jenozKc"
Defensive patterns
Strategy: validation
Validate before calling
import re
def needs_scheme(u):
return not re.match(r'^[a-zA-Z][a-zA-Z0-9+.-]*://', u)
if needs_scheme(arg):
arg = 'https://' + arg # or reject, or prefix ytsearch: Type guard
def is_full_url(u):
return bool(re.match(r'^https?://\S+$', u)) Try / catch
try:
ydl.download([arg])
except DownloadError as e:
if 'not a valid URL' in str(e):
arg = 'ytsearch:' + arg # or fix the URL and retry
else:
raise Prevention
- Default --default-search ytsearch in wrapper scripts if users pass IDs/titles
- Validate inputs have a scheme before invoking youtube-dl from code
- Check variables are set before passing them as URLs
When it happens
Trigger: Passing a scheme-less argument that is not a domain path, e.g. 'youtube-dl BaW_jenozKc' or 'youtube-dl some random text', with default --default-search fixup_error (the default when unset) or explicit 'error'.
Common situations: Users pasting video IDs or titles instead of URLs, missing https:// prefix on copied links, or scripts passing unquoted/unset variables.
Related errors
- Invalid URL: %r . Call youtube-dl like this: youtube-dl -v
- Unsupported URL: %s
- Invalid URL: %s
- Incomplete YouTube ID %s. URL %s looks truncated.
- error running
AI-assisted analysis of ytdl-org/youtube-dl@956b8c5855 (2026-08-14).
Data as JSON: /api/errors/99605c91fe42f373.
Report an issue: GitHub.