{"record":{"id":"e1c5c61c6e0cfb5d","repo":"ytdl-org/youtube-dl","slug":"operator-s-does-not-support-string-values","errorCode":null,"errorMessage":"Operator %s does not support string values!","messagePattern":"Operator (.+?) does not support string values!","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"youtube_dl/utils.py","lineNumber":4898,"sourceCode":"            (?P<quote>[\"\\'])(?P<quotedstrval>(?:\\\\.|(?!(?P=quote)|\\\\).)+?)(?P=quote)|\n            (?P<strval>(?![0-9.])[a-z0-9A-Z]*)\n        )\n        \\s*$\n        ''' % '|'.join(map(re.escape, COMPARISON_OPERATORS.keys())))\n    m = operator_rex.search(filter_part)\n    if m:\n        op = COMPARISON_OPERATORS[m.group('op')]\n        actual_value = dct.get(m.group('key'))\n        if (m.group('quotedstrval') is not None\n            or m.group('strval') is not None\n            # If the original field is a string and matching comparisonvalue is\n            # a number we should respect the origin of the original field\n            # and process comparison value as a string (see\n            # https://github.com/ytdl-org/youtube-dl/issues/11082).\n            or actual_value is not None and m.group('intval') is not None\n                and isinstance(actual_value, compat_str)):\n            if m.group('op') not in ('=', '!='):\n                raise ValueError(\n                    'Operator %s does not support string values!' % m.group('op'))\n            comparison_value = m.group('quotedstrval') or m.group('strval') or m.group('intval')\n            quote = m.group('quote')\n            if quote is not None:\n                comparison_value = comparison_value.replace(r'\\%s' % quote, quote)\n        else:\n            try:\n                comparison_value = int(m.group('intval'))\n            except ValueError:\n                comparison_value = parse_filesize(m.group('intval'))\n                if comparison_value is None:\n                    comparison_value = parse_filesize(m.group('intval') + 'B')\n                if comparison_value is None:\n                    raise ValueError(\n                        'Invalid integer value %r in filter part %r' % (\n                            m.group('intval'), filter_part))\n        if actual_value is None:\n            return m.group('none_inclusive')","sourceCodeStart":4880,"sourceCodeEnd":4916,"githubUrl":"https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/utils.py#L4880-L4916","documentation":"Raised by _match_one() in youtube_dl.utils while evaluating a --match-filter expression. The filter compares a field to a quoted or bare string value using a comparison operator other than = or != (e.g. <, <=, >, >=, ~=). Ordering/regex operators only work on numeric values, so applying one to a string comparison value is rejected with ValueError. The check also fires when the field's actual value is a string but the filter supplies a bare number (e.g. likes>100 against a string field), honoring the field's origin (issue #11082).","triggerScenarios":"Running youtube-dl --match-filter \"title>'foo'\" or any filter like field<value / field>value / field~=value where value is quoted ('...' or \"...\") or bare text; or a filter like likes>100 where the extractor reports likes as a string. Only = and != accept string comparison values.","commonSituations":"Users writing match-filters that compare text fields lexicographically (title>'A', duration~='long'); filters written against fields that one extractor types as int and another as string; copy-pasted filter examples that assume numeric fields.","solutions":["Use only = or != when comparing string fields, e.g. --match-filter \"ext!=mkv\".","Compare numeric fields numerically (view_count>1000) and verify the extractor populates that field as a number.","For substring/regex needs on strings, rely on = with the supported semantics or pre-filter downloads with your own script instead of the filter DSL.","Quote string values only for =/!= comparisons; drop quotes for numeric comparisons."],"exampleFix":"# before\nyoutube-dl --match-filter \"title>'Tutorial'\" URL  # ValueError: Operator > does not support string values!\n\n# after\nyoutube-dl --match-filter \"title!='Tutorial'\" URL  # equality on strings is allowed","handlingStrategy":"validation","validationCode":"import re\n# only = and != may take string comparison values\n_BAD = re.compile(r\"[<>]=?|~=\")\n\ndef check_filter(filter_str):\n    for part in filter_str.split('&'):\n        m = re.match(r'^([a-z_]+)\\s*(=|!=|<|<=|>|>=|~=)\\s*(.+)$', part.strip())\n        if m and m.group(2) not in ('=', '!='):\n            val = m.group(3)\n            if not re.fullmatch(r'\\d+([KMG]B?)?', val):\n                raise ValueError('operator %s cannot take string value %r' % (m.group(2), val))","typeGuard":"def is_safe_string_filter(op: str, value: str) -> bool:\n    return op in ('=', '!=') or value.lstrip('-').isdigit()","tryCatchPattern":"from youtube_dl.utils import match_str\ntry:\n    ok = match_str('title>\\'x\\'', info)\nexcept ValueError as e:\n    # rewrite filter to use =/!= or drop the part\n    ok = None","preventionTips":["Reserve <, <=, >, >=, ~= for numeric fields; use =/!= for strings.","Check with --dump-json whether the field is numeric before writing a numeric filter.","Test filter strings with a dry-run (--simulate) before batch downloads."],"tags":["match-filter","cli","validation","user-input"],"backgroundTag":null,"analyzedSha":"956b8c585591b401a543e409accb163eeaaa1193","analyzedAt":"2026-08-14T18:59:47.863Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}