antlr/antlr4 · error · Exception

tag delimiters out of order in pattern: %s

Error message

tag delimiters out of order in pattern: %s

What it means

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 '>'.

Source

Thrown at runtime/Python3/src/antlr4/tree/ParseTreePatternMatcher.py:336

            elif p == pattern.find(self.start, p):
                starts.append(p)
                p += len(self.start)
            elif p == pattern.find(self.stop, p):
                stops.append(p)
                p += len(self.stop)
            else:
                p += 1

        nt = len(starts)

        if nt > len(stops):
            raise Exception("unterminated tag in pattern: " + pattern)
        if nt < len(stops):
            raise Exception("missing start tag in pattern: " + pattern)

        for i in range(0, nt):
            if starts[i] >= stops[i]:
                raise Exception("tag delimiters out of order in pattern: " + pattern)

        # collect into chunks now
        if nt==0:
            chunks.append(TextChunk(pattern))

        if nt>0 and starts[0]>0: # copy text up to first tag into chunks
            text = pattern[0:starts[0]]
            chunks.add(TextChunk(text))

        for i in range(0, nt):
            # copy inside of <tag>
            tag = pattern[starts[i] + len(self.start) : stops[i]]
            ruleOrToken = tag
            label = None
            colon = tag.find(':')
            if colon >= 0:
                label = tag[0:colon]
                ruleOrToken = tag[colon+1 : len(tag)]

View on GitHub (pinned to 7d5770395b)

Solutions

  1. Escape all literal angle brackets so only real tags contribute delimiters
  2. Reorder the pattern so every tag is '<...>'
  3. Build patterns programmatically from validated tag components instead of string concatenation

Example fix

# before
pattern = parser.compilePattern('> <ID>', 0)

# after
pattern = parser.compilePattern('<ID>', 0)
Defensive patterns

Strategy: validation

Validate before calling

import re
# quick check: no stop delimiter before its matching start
positions = [(m.start(), 'start') for m in re.finditer(re.escape('<'), pattern)] + \
            [(m.start(), 'stop') for m in re.finditer(re.escape('>'), pattern)]
open_tag = False
for pos, kind in sorted(positions):
    open_tag = (kind == 'start') if not open_tag or kind == 'start' else open_tag
    if kind == 'stop' and not open_tag:
        raise ValueError('tag delimiters out of order')

Try / catch

try:
    p = matcher.compileTreePattern(pat, idx)
except Exception as e:
    if 'out of order' in str(e):
        # reorder / escape delimiters
        ...

Prevention

When it happens

Trigger: Compiling a pattern like '>ID<' or 'a > b < c' where stops and starts are interleaved so starts[i] >= stops[i] for some pair.

Common situations: Unescaped angle brackets in surrounding text producing reversed delimiter order, or hand-built pattern strings concatenated in the wrong order.

Related errors


AI-assisted analysis of antlr/antlr4@7d5770395b (2026-08-14). Data as JSON: /api/errors/377c5c4bdf20e89e. Report an issue: GitHub.