antlr/antlr4 · error · InvalidOperationException

release() called with an invalid marker.

Error message

release() called with an invalid marker.

What it means

UnbufferedTokenStream implements Mark()/Release() as a strictly LIFO stack: Mark() returns -numMarkers-1 (so marks are -1, -2, ...) and Release(marker) requires marker == -numMarkers. The thrown InvalidOperationException means the marker passed to Release() is not the most recently acquired, still-open mark. The stream cannot release out of order because each mark pins a buffer window.

Source

Thrown at runtime/CSharp/src/UnbufferedTokenStream.cs:298

        /// is called in the wrong order.</p>
        /// </remarks>
        public virtual int Mark()
        {
            if (numMarkers == 0)
            {
                lastTokenBufferStart = lastToken;
            }
            int mark = -numMarkers - 1;
            numMarkers++;
            return mark;
        }

        public virtual void Release(int marker)
        {
            int expectedMark = -numMarkers;
            if (marker != expectedMark)
            {
                throw new InvalidOperationException("release() called with an invalid marker.");
            }
            numMarkers--;
            if (numMarkers == 0)
            {
                // can we release buffer?
                if (p > 0)
                {
                    // Copy tokens[p]..tokens[n-1] to tokens[0]..tokens[(n-1)-p], reset ptrs
                    // p is last valid token; move nothing if p==n as we have no valid char
                    System.Array.Copy(tokens, p, tokens, 0, n - p);
                    // shift n-p tokens from p to 0
                    n = n - p;
                    p = 0;
                }
                lastTokenBufferStart = lastToken;
            }
        }

View on GitHub (pinned to 7d5770395b)

Solutions

  1. Release markers in strict reverse order of acquisition (last Mark() released first) and never release the same marker twice
  2. Wrap usage in try/finally so the matching Release() always runs even when parsing throws
  3. Check the invariant before calling: marker must equal the value returned by the most recent, unreleased Mark() (i.e. -(numMarkers))
  4. If you only need a single checkpoint, keep exactly one mark at a time: Mark() once, Release() once, repeat

Example fix

// before
int m = stream.Mark();
Parse();
stream.Release(m);
stream.Release(m); // second release throws

// after
int m = stream.Mark();
try {
    Parse();
}
finally {
    stream.Release(m); // exactly once, in LIFO order
}
Defensive patterns

Strategy: validation

Validate before calling

// C#: release only the top-of-stack mark; marks are -1, -2, ... in LIFO order
// track open marks yourself when nesting
var openMarks = new Stack<int>();
int m = stream.Mark();
openMarks.Push(m);
if (openMarks.Peek() == m) { stream.Release(openMarks.Pop()); } // valid only when m == last Mark() unreleased

Try / catch

try { int m = stream.Mark(); try { Parse(stream); } finally { stream.Release(m); } } catch (InvalidOperationException ex) when (ex.Message.Contains("invalid marker")) { // mark stack corrupted earlier: reset the stream and restart parse from a fresh UnbufferedTokenStream }

Prevention

When it happens

Trigger: Calling Release(m) twice for the same m; calling Release(0) (marks are negative, never 0); releasing marks in a non-LIFO order (release mark -2 while -1 is still open); releasing a marker obtained from a different token stream or after an exception path already released it; calling Release() when numMarkers==0.

Common situations: Manually managing mark/release around backtracking without try/finally, so an early exception or return skips one release and shifts the stack; mixing markers between a CommonTokenStream and an UnbufferedTokenStream; porting code that assumed Java's index-style markers (0,1,2...) instead of ANTLR 4's negative stack markers.

Related errors


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