{"record":{"id":"377c5c4bdf20e89e","repo":"antlr/antlr4","slug":"tag-delimiters-out-of-order-in-pattern-s","errorCode":null,"errorMessage":"tag delimiters out of order in pattern: %s","messagePattern":"tag delimiters out of order in pattern: (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"runtime/Python3/src/antlr4/tree/ParseTreePatternMatcher.py","lineNumber":336,"sourceCode":"            elif p == pattern.find(self.start, p):\n                starts.append(p)\n                p += len(self.start)\n            elif p == pattern.find(self.stop, p):\n                stops.append(p)\n                p += len(self.stop)\n            else:\n                p += 1\n\n        nt = len(starts)\n\n        if nt > len(stops):\n            raise Exception(\"unterminated tag in pattern: \" + pattern)\n        if nt < len(stops):\n            raise Exception(\"missing start tag in pattern: \" + pattern)\n\n        for i in range(0, nt):\n            if starts[i] >= stops[i]:\n                raise Exception(\"tag delimiters out of order in pattern: \" + pattern)\n\n        # collect into chunks now\n        if nt==0:\n            chunks.append(TextChunk(pattern))\n\n        if nt>0 and starts[0]>0: # copy text up to first tag into chunks\n            text = pattern[0:starts[0]]\n            chunks.add(TextChunk(text))\n\n        for i in range(0, nt):\n            # copy inside of <tag>\n            tag = pattern[starts[i] + len(self.start) : stops[i]]\n            ruleOrToken = tag\n            label = None\n            colon = tag.find(':')\n            if colon >= 0:\n                label = tag[0:colon]\n                ruleOrToken = tag[colon+1 : len(tag)]","sourceCodeStart":318,"sourceCodeEnd":354,"githubUrl":"https://github.com/antlr/antlr4/blob/7d5770395bb7b02eb56e7c62662cb1d7c08f42a3/runtime/Python3/src/antlr4/tree/ParseTreePatternMatcher.py#L318-L354","documentation":"Raised by ParseTreePatternMatcher.split() when the i-th start delimiter does not occur before the i-th stop delimiter, e.g. '>...<' order. Delimiters must alternate correctly: each tag's '<' must precede its paired '>'.","triggerScenarios":"Compiling a pattern like '>ID<' or 'a > b < c' where stops and starts are interleaved so starts[i] >= stops[i] for some pair.","commonSituations":"Unescaped angle brackets in surrounding text producing reversed delimiter order, or hand-built pattern strings concatenated in the wrong order.","solutions":["Escape all literal angle brackets so only real tags contribute delimiters","Reorder the pattern so every tag is '<...>'","Build patterns programmatically from validated tag components instead of string concatenation"],"exampleFix":"# before\npattern = parser.compilePattern('> <ID>', 0)\n\n# after\npattern = parser.compilePattern('<ID>', 0)","handlingStrategy":"validation","validationCode":"import re\n# quick check: no stop delimiter before its matching start\npositions = [(m.start(), 'start') for m in re.finditer(re.escape('<'), pattern)] + \\\n            [(m.start(), 'stop') for m in re.finditer(re.escape('>'), pattern)]\nopen_tag = False\nfor pos, kind in sorted(positions):\n    open_tag = (kind == 'start') if not open_tag or kind == 'start' else open_tag\n    if kind == 'stop' and not open_tag:\n        raise ValueError('tag delimiters out of order')","typeGuard":null,"tryCatchPattern":"try:\n    p = matcher.compileTreePattern(pat, idx)\nexcept Exception as e:\n    if 'out of order' in str(e):\n        # reorder / escape delimiters\n        ...","preventionTips":["Ensure delimiters alternate '<...>' correctly","Escape all literal angle brackets"],"tags":["antlr","python","parse-tree-matching","pattern-compile"],"backgroundTag":null,"analyzedSha":"7d5770395bb7b02eb56e7c62662cb1d7c08f42a3","analyzedAt":"2026-08-14T14:47:56.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}