{"record":{"id":"046d34e50662bc7f","repo":"ytdl-org/youtube-dl","slug":"invalid-filter-part-r","errorCode":null,"errorMessage":"Invalid filter part %r","messagePattern":"Invalid filter part %r","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"youtube_dl/utils.py","lineNumber":4933,"sourceCode":"        if actual_value is None:\n            return m.group('none_inclusive')\n        return op(actual_value, comparison_value)\n\n    UNARY_OPERATORS = {\n        '': lambda v: (v is True) if isinstance(v, bool) else (v is not None),\n        '!': lambda v: (v is False) if isinstance(v, bool) else (v is None),\n    }\n    operator_rex = re.compile(r'''(?x)\\s*\n        (?P<op>%s)\\s*(?P<key>[a-z_]+)\n        \\s*$\n        ''' % '|'.join(map(re.escape, UNARY_OPERATORS.keys())))\n    m = operator_rex.search(filter_part)\n    if m:\n        op = UNARY_OPERATORS[m.group('op')]\n        actual_value = dct.get(m.group('key'))\n        return op(actual_value)\n\n    raise ValueError('Invalid filter part %r' % filter_part)\n\n\ndef match_str(filter_str, dct):\n    \"\"\" Filter a dictionary with a simple string syntax. Returns True (=passes filter) or false \"\"\"\n\n    return all(\n        _match_one(filter_part, dct) for filter_part in filter_str.split('&'))\n\n\ndef match_filter_func(filter_str):\n    def _match_func(info_dict):\n        if match_str(filter_str, info_dict):\n            return None\n        else:\n            video_title = info_dict.get('title', info_dict.get('id', 'video'))\n            return '%s does not pass filter %s, skipping ..' % (video_title, filter_str)\n    return _match_func\n","sourceCodeStart":4915,"sourceCodeEnd":4951,"githubUrl":"https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/utils.py#L4915-L4951","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Rewrite the part as <key><op><value> (e.g. view_count>1000, ext=mp4, !is_live).","Use only '&' to combine parts; '&&' produces an empty part and triggers this error.","Check the key is lowercase letters/underscores only and the operator is one of = != < <= > >= ~=.","Split complex logic across multiple youtube-dl invocations or a wrapper script, since OR/parens are not supported."],"exampleFix":"# before\nyoutube-dl --match-filter \"ext==mp4 && view_count>1000\" URL  # '==' and '&&' are invalid → Invalid filter part\n\n# after\nyoutube-dl --match-filter \"ext=mp4&view_count>1000\" URL","handlingStrategy":"validation","validationCode":"import re\nBINARY = re.compile(r'^[a-z_]+\\s*(=|!=|<|<=|>|>=|~=)\\s*.+$')\nUNARY = re.compile(r'^!?[a-z_]+$')\n\ndef validate_match_filter(filter_str):\n    for part in filter_str.split('&'):\n        p = part.strip()\n        if not p or not (BINARY.match(p) or UNARY.match(p)):\n            raise ValueError('Invalid filter part %r' % part)","typeGuard":"def is_valid_filter_part(part: str) -> bool:\n    import re\n    return bool(re.match(r'^[a-z_]+\\s*(=|!=|<|<=|>|>=|~=)\\s*.+$', part) or re.match(r'^!?[a-z_]+$', part))","tryCatchPattern":"from youtube_dl.utils import match_str\ntry:\n    match_str(filter_str, info_dict)\nexcept ValueError as e:\n    log.warning('skipping malformed filter: %s', e)\n    accept = True  # or fail fast, per policy","preventionTips":["Combine parts only with single '&', never '&&', ',', or ';'.","Stick to the grammar key<op>value or !key; there is no OR or parentheses.","Validate filter strings at startup (regex above) so bad user input fails early."],"tags":["match-filter","cli","validation","user-input"],"backgroundTag":null,"analyzedSha":"956b8c585591b401a543e409accb163eeaaa1193","analyzedAt":"2026-08-14T18:59:47.863Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}