{"id":"fb6116844a3110b6","repo":"pypa/pip","slug":"invalid-glob-r-mismatching-set-marker-or","errorCode":null,"errorMessage":"invalid glob %r: mismatching set marker '{' or '}'","messagePattern":"invalid glob %r: mismatching set marker '(.+?)'","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/distlib/util.py","lineNumber":1441,"sourceCode":"\n\n#\n# Glob functionality\n#\n\nRICH_GLOB = re.compile(r'\\{([^}]*)\\}')\n_CHECK_RECURSIVE_GLOB = re.compile(r'[^/\\\\,{]\\*\\*|\\*\\*[^/\\\\,}]')\n_CHECK_MISMATCH_SET = re.compile(r'^[^{]*\\}|\\{[^}]*$')\n\n\ndef iglob(path_glob):\n    \"\"\"Extended globbing function that supports ** and {opt1,opt2,opt3}.\"\"\"\n    if _CHECK_RECURSIVE_GLOB.search(path_glob):\n        msg = \"\"\"invalid glob %r: recursive glob \"**\" must be used alone\"\"\"\n        raise ValueError(msg % path_glob)\n    if _CHECK_MISMATCH_SET.search(path_glob):\n        msg = \"\"\"invalid glob %r: mismatching set marker '{' or '}'\"\"\"\n        raise ValueError(msg % path_glob)\n    return _iglob(path_glob)\n\n\ndef _iglob(path_glob):\n    rich_path_glob = RICH_GLOB.split(path_glob, 1)\n    if len(rich_path_glob) > 1:\n        assert len(rich_path_glob) == 3, rich_path_glob\n        prefix, set, suffix = rich_path_glob\n        for item in set.split(','):\n            for path in _iglob(''.join((prefix, item, suffix))):\n                yield path\n    else:\n        if '**' not in path_glob:\n            for item in std_iglob(path_glob):\n                yield item\n        else:\n            prefix, radical = path_glob.split('**', 1)\n            if prefix == '':","sourceCodeStart":1423,"sourceCodeEnd":1459,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_vendor/distlib/util.py#L1423-L1459","documentation":"Raised by iglob() when brace set markers '{' and '}' are mismatched (matched by _CHECK_MISMATCH_SET). distlib supports brace expansion like '{src,tests}/*.py' but rejects patterns with an unmatched '}' at the start or an unmatched '{' with no closing '}', raising ValueError 'mismatching set marker'.","triggerScenarios":"iglob('src/{a,b/*.py') (missing '}'), iglob('src/a,b}/x') (missing '{'), or any pattern where braces are unbalanced.","commonSituations":"Programmatic glob construction that omits a brace, copy-paste from configs that stripped a brace, or escaping mistakes.","solutions":["Balance the braces: 'src/{a,b}/*.py'.","If you did not intend a set, remove the stray '{' or '}'.","Count '{' and '}' in the pattern and ensure they are equal and properly nested."],"exampleFix":"// before\nlist(iglob('src/{a,b/*.py'))\n// after\nlist(iglob('src/{a,b}/*.py'))","handlingStrategy":"validation","validationCode":"def safe_iglob(pattern):\n    if pattern.count('{') != pattern.count('}'):\n        raise ValueError('unbalanced brace set markers: %r' % pattern)\n    from distlib.util import iglob\n    return list(iglob(pattern))","typeGuard":null,"tryCatchPattern":"from distlib.util import iglob\ntry:\n    matches = list(iglob(pattern))\nexcept ValueError as e:\n    if 'mismatching set marker' in str(e):\n        pattern = pattern.replace('{', '').replace('}', '')  # or fix brackets\n        matches = list(iglob(pattern))\n    else:\n        raise","preventionTips":["Ensure '{' and '}' are balanced in glob patterns.","Build brace sets programmatically and add the closing brace in the same step.","Validate brace balance before invoking iglob()."],"tags":["glob","filesystem","validation","packaging"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}