ytdl-org/youtube-dl · error · ExtractorError

No video formats found!

Error message

No video formats found!

What it means

Raised by xpath_attr when no element matching (xpath, key) has the requested attribute — find_xpath_attr returns None, no default is given, and fatal=True. It is the attribute-counterpart of the element error: the element may exist, but the @key attribute the extractor requires is missing.

Source

Thrown at youtube_dl/YoutubeDL.py:1759

        else:
            formats = info_dict['formats']

        def is_wellformed(f):
            url = f.get('url')
            if not url:
                self.report_warning(
                    '"url" field is missing or empty - skipping format, '
                    'there is an error in extractor')
                return False
            if isinstance(url, bytes):
                sanitize_string_field(f, 'url')
            return True

        # Filter out malformed formats for better extraction robustness
        formats = list(filter(is_wellformed, formats or []))

        if not formats:
            raise ExtractorError('No video formats found!')

        formats_dict = {}

        # We check that all the formats have the format and format_id fields
        for i, format in enumerate(formats):
            sanitize_string_field(format, 'format_id')
            sanitize_numeric_fields(format)
            format['url'] = sanitize_url(format['url'])
            if not format.get('format_id'):
                format['format_id'] = compat_str(i)
            else:
                # Sanitize format_id from characters used in format selector expression
                format['format_id'] = re.sub(r'[\s,/+\[\]()]', '_', format['format_id'])
            format_id = format['format_id']
            if format_id not in formats_dict:
                formats_dict[format_id] = []
            formats_dict[format_id].append(format)

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Pass default=None / fatal=False and handle the miss at the call site when the attribute is genuinely optional.
  2. Dump the received XML and confirm the attribute name — update the XPath to '//Stream[@url]' or read the renamed attribute.
  3. Update youtube-dl / use yt-dlp for built-in extractor breakage.
  4. Provide name='stream url' to get a human-readable error identifying the field.

Example fix

# before
url = xpath_attr(fmt, 'Stream', 'url', fatal=True)

# after
url = xpath_attr(fmt, 'Stream', 'url', default=None) or xpath_text(fmt, 'Stream/url')
Defensive patterns

Strategy: validation

Validate before calling

from youtube_dl.utils import find_xpath_attr

# pre-check attribute presence
node = find_xpath_attr(doc, '//Stream', 'url')
if node is None:
    url = fallback_url
else:
    url = node.attrib['url']

Try / catch

from youtube_dl.utils import ExtractorError, xpath_attr
try:
    url = xpath_attr(node, 'Stream', 'url', name='stream url', fatal=True)
except ExtractorError as e:
    if 'Could not find XML attribute' in str(e):
        url = xpath_text(node, 'Stream/text()', default=None)  # schema moved it
    else:
        raise

Prevention

When it happens

Trigger: xpath_attr(node, '//Stream', 'url', fatal=True) where the Stream nodes lack a url attribute (renamed to href, moved to child text, or dropped). The message shows 'xpath[@key]' (or the caller's name=) identifying the exact attribute expected.

Common situations: API schema changes renaming attributes; conditional attributes only present for some items; responses from a different endpoint/version than the extractor expects; namespace-qualified attributes the plain XPath misses.

Related errors


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