ytdl-org/youtube-dl · error · ValueError

Invalid filter part %r

Error message

Invalid filter part %r

What it means

Raised by _match_one() in youtube_dl.utils when a single --match-filter part matches neither the binary comparison grammar (<key><op><value>, =/!=/</<=/>/>=/~= with an int, filesize, or quoted/bare string) nor the unary grammar (key or !key). It is the catch-all syntax error for the filter mini-language; match_str() splits on '&' and evaluates each part with _match_one, so one malformed part fails the whole filter.

Source

Thrown at youtube_dl/utils.py:4933

        if actual_value is None:
            return m.group('none_inclusive')
        return op(actual_value, comparison_value)

    UNARY_OPERATORS = {
        '': lambda v: (v is True) if isinstance(v, bool) else (v is not None),
        '!': lambda v: (v is False) if isinstance(v, bool) else (v is None),
    }
    operator_rex = re.compile(r'''(?x)\s*
        (?P<op>%s)\s*(?P<key>[a-z_]+)
        \s*$
        ''' % '|'.join(map(re.escape, UNARY_OPERATORS.keys())))
    m = operator_rex.search(filter_part)
    if m:
        op = UNARY_OPERATORS[m.group('op')]
        actual_value = dct.get(m.group('key'))
        return op(actual_value)

    raise ValueError('Invalid filter part %r' % filter_part)


def match_str(filter_str, dct):
    """ Filter a dictionary with a simple string syntax. Returns True (=passes filter) or false """

    return all(
        _match_one(filter_part, dct) for filter_part in filter_str.split('&'))


def match_filter_func(filter_str):
    def _match_func(info_dict):
        if match_str(filter_str, info_dict):
            return None
        else:
            video_title = info_dict.get('title', info_dict.get('id', 'video'))
            return '%s does not pass filter %s, skipping ..' % (video_title, filter_str)
    return _match_func

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Rewrite the part as <key><op><value> (e.g. view_count>1000, ext=mp4, !is_live).
  2. Use only '&' to combine parts; '&&' produces an empty part and triggers this error.
  3. Check the key is lowercase letters/underscores only and the operator is one of = != < <= > >= ~=.
  4. Split complex logic across multiple youtube-dl invocations or a wrapper script, since OR/parens are not supported.

Example fix

# before
youtube-dl --match-filter "ext==mp4 && view_count>1000" URL  # '==' and '&&' are invalid → Invalid filter part

# after
youtube-dl --match-filter "ext=mp4&view_count>1000" URL
Defensive patterns

Strategy: validation

Validate before calling

import re
BINARY = re.compile(r'^[a-z_]+\s*(=|!=|<|<=|>|>=|~=)\s*.+$')
UNARY = re.compile(r'^!?[a-z_]+$')

def validate_match_filter(filter_str):
    for part in filter_str.split('&'):
        p = part.strip()
        if not p or not (BINARY.match(p) or UNARY.match(p)):
            raise ValueError('Invalid filter part %r' % part)

Type guard

def is_valid_filter_part(part: str) -> bool:
    import re
    return bool(re.match(r'^[a-z_]+\s*(=|!=|<|<=|>|>=|~=)\s*.+$', part) or re.match(r'^!?[a-z_]+$', part))

Try / catch

from youtube_dl.utils import match_str
try:
    match_str(filter_str, info_dict)
except ValueError as e:
    log.warning('skipping malformed filter: %s', e)
    accept = True  # or fail fast, per policy

Prevention

When it happens

Trigger: Running --match-filter with a part that is empty, contains an unknown key character (keys must be [a-z_]), an unsupported operator (e.g. field==value, field>=), reversed order (100<views), a lone comparison symbol, or separators other than '&' (semicolons and commas are not recognized and end up inside the part).

Common situations: Typos and experimentation with the filter syntax; assuming full boolean expressions (OR, parentheses) exist; using '&&' which yields an empty part after splitting on '&'; copying filter syntax from yt-dlp (which supports more operators) into youtube-dl.

Related errors


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