antlr/antlr4 · error · ArgumentOutOfRangeException

start {start} or stop {stop} not in 0..{tokens.Count - 1}

Error message

start {start} or stop {stop} not in 0..{tokens.Count - 1}

What it means

GetTokens(start, stop, types) filters tokens in the inclusive range start..stop and requires both endpoints to be within the currently buffered list (0 <= start, stop < tokens.Count). Out-of-range endpoints indicate the caller computed the range from stale or external positions. Note the quirk that start > stop returns null rather than throwing — only out-of-bounds bounds throw.

Source

Thrown at runtime/CSharp/src/BufferedTokenStream.cs:403

        }

        /// <summary>
        /// Given a start and stop index, return a
        /// <c>List</c>
        /// of all tokens in
        /// the token type
        /// <c>BitSet</c>
        /// .  Return
        /// <see langword="null"/>
        /// if no tokens were found.  This
        /// method looks at both on and off channel tokens.
        /// </summary>
        public virtual IList<IToken> GetTokens(int start, int stop, BitSet types)
        {
            LazyInit();
            if (start < 0 || stop >= tokens.Count || stop < 0 || start >= tokens.Count)
            {
                throw new ArgumentOutOfRangeException("start " + start + " or stop " + stop + " not in 0.." + (tokens.Count - 1));
            }
            if (start > stop)
            {
                return null;
            }
            // list = tokens[start:stop]:{T t, t.getType() in types}
            IList<IToken> filteredTokens = new List<IToken>();
            for (int i = start; i <= stop; i++)
            {
                IToken t = tokens[i];
                if (types == null || types.Get(t.Type))
                {
                    filteredTokens.Add(t);
                }
            }
            if (filteredTokens.Count == 0)
            {
                filteredTokens = null;

View on GitHub (pinned to 7d5770395b)

Solutions

  1. Clamp both endpoints to [0, stream.Size - 1] before calling GetTokens
  2. Always derive start/stop from TokenIndex values of tokens obtained from the same stream instance
  3. Handle the null return for start > stop explicitly rather than expecting an empty list

Example fix

// before
IList<IToken> ctx = stream.GetTokens(errOffendingToken.TokenIndex - 5, errOffendingToken.TokenIndex + 5, null); // throws near EOF

// after
int start = Math.Max(0, errToken.TokenIndex - 5);
int stop = Math.Min(errToken.TokenIndex + 5, stream.Size - 1);
IList<IToken> ctx = start <= stop ? stream.GetTokens(start, stop, null) : null;
Defensive patterns

Strategy: validation

Validate before calling

int start = Math.Max(0, requestedStart);
int stop = Math.Min(requestedStop, stream.Size - 1);
IList<IToken> tokens = start <= stop ? stream.GetTokens(start, stop, types) : null;

Prevention

When it happens

Trigger: Calling GetTokens with start or stop beyond the buffered tokens, e.g. stop taken from a token of a different (unbuffered or re-created) stream, negative indices, or calling before LazyInit/Size has fetched enough tokens (LazyInit runs first, but the buffer only extends to what has been consumed).

Common situations: Syntax-error highlighters asking for GetTokens(badToken.TokenIndex - 5, badToken.TokenIndex + 5) near the end of input; token-stream rewriting code that mixes indices from a before/after stream; IDE integrations computing ranges from editor positions instead of token indices.

Related errors


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