antlr/antlr4 · error · ArgumentOutOfRangeException

LT(${i}) gives negative index

Error message

LT(${i}) gives negative index

What it means

LT(i) maps positive lookahead to index p+i-1, and only i == -1 is special-cased to return the previous token. If the computed index is negative, the request looks before the beginning of the available token stream and is rejected. LT(0) and lookahead values below -1 are the usual causes.

Source

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

            int bufferStartIndex = GetBufferStartIndex();
            if (i < bufferStartIndex || i >= bufferStartIndex + n)
            {
                throw new ArgumentOutOfRangeException("get(" + i + ") outside buffer: " + bufferStartIndex + ".." + (bufferStartIndex + n));
            }
            return tokens[i - bufferStartIndex];
        }

        public virtual IToken LT(int i)
        {
            if (i == -1)
            {
                return lastToken;
            }
            Sync(i);
            int index = p + i - 1;
            if (index < 0)
            {
                throw new ArgumentOutOfRangeException("LT(" + i + ") gives negative index");
            }
            if (index >= n)
            {
                System.Diagnostics.Debug.Assert(n > 0 && tokens[n - 1].Type == TokenConstants.EOF);
                return tokens[n - 1];
            }
            return tokens[index];
        }

        public virtual int LA(int i)
        {
            return LT(i).Type;
        }

        public virtual ITokenSource TokenSource
        {
            get
            {

View on GitHub (pinned to 7d5770395b)

Solutions

  1. Use LT(1) for the current lookahead token and LT(-1) for the previous token.
  2. Do not call LT(0).
  3. Ensure lookahead loops start at i = 1.

Example fix

// before
IToken current = tokens.LT(0);

// after
IToken current = tokens.LT(1);
Defensive patterns

Strategy: validation

Validate before calling

if (i != -1 && i < 1)
    throw new ArgumentOutOfRangeException(nameof(i), "Use LT(1) or LT(-1).");
var token = tokens.LT(i);

Try / catch

try { var t = tokens.LT(i); }
catch (ArgumentOutOfRangeException ex) when (ex.Message.StartsWith("LT(")) { /* correct lookahead index */ }

Prevention

When it happens

Trigger: Calling LT(0) at the start of the stream; calling LT(-2) or smaller; generic loops that call LT(i) beginning at zero; or code that assumes LT(0) returns the current token or null.

Common situations: Token-iteration helpers written for a different API; lookahead loops using inclusive zero-based indexes; porting from another runtime whose LT semantics differ.

Related errors


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