antlr/antlr4 · error · IndexOutOfBoundsException

start {} or stop {} not in 0..{}

Error message

start {} or stop {} not in 0..{}

What it means

getTokens(int start, int stop, Set<Integer> types) requires both endpoints to lie inside the current token buffer (0..size()-1); otherwise it throws IndexOutOfBoundsException. Note the asymmetry with the two-argument get(start, stop), which returns null for negative bounds instead of throwing. lazyInit() runs first, but that only guarantees the first token exists, not that the whole range is fetched.

Source

Thrown at runtime/Java/src/org/antlr/v4/runtime/BufferedTokenStream.java:281

        fetchedEOF = false;
    }

    public List<Token> getTokens() { return tokens; }

    public List<Token> getTokens(int start, int stop) {
        return getTokens(start, stop, null);
    }

    /** Given a start and stop index, return a List of all tokens in
     *  the token type BitSet.  Return null if no tokens were found.  This
     *  method looks at both on and off channel tokens.
     */
    public List<Token> getTokens(int start, int stop, Set<Integer> types) {
        lazyInit();
		if ( start<0 || stop>=tokens.size() ||
			 stop<0  || start>=tokens.size() )
		{
			throw new IndexOutOfBoundsException("start "+start+" or stop "+stop+
												" not in 0.."+(tokens.size()-1));
		}
        if ( start>stop ) return null;

        // list = tokens[start:stop]:{T t, t.getType() in types}
        List<Token> filteredTokens = new ArrayList<Token>();
        for (int i=start; i<=stop; i++) {
            Token t = tokens.get(i);
            if ( types==null || types.contains(t.getType()) ) {
                filteredTokens.add(t);
            }
        }
        if ( filteredTokens.isEmpty() ) {
            filteredTokens = null;
        }
        return filteredTokens;
    }

View on GitHub (pinned to 7d5770395b)

Solutions

  1. Clamp: int stop = Math.min(stop, tokens.size() - 1) and reject start < 0 before calling
  2. Call tokens.fill() before ranged queries so size() reflects the whole input
  3. Return early (or null) yourself when start > stop or bounds are invalid instead of relying on the exception

Example fix

// before
List<Token> all = tokens.getTokens(0, tokens.size(), types); // throws

// after
tokens.fill();
List<Token> all = tokens.getTokens(0, tokens.size() - 1, types);
Defensive patterns

Strategy: validation

Validate before calling

tokens.fill();
int stop = Math.min(requestedStop, tokens.size() - 1);
int start = Math.max(requestedStart, 0);
if (start <= stop) { List<Token> ts = tokens.getTokens(start, stop, types); }

Prevention

When it happens

Trigger: Calling getTokens(0, tokens.size(), null) (stop one past the end); passing stop from an unfilled stream's estimated size; passing -1 sentinels that the two-arg overload tolerates but this overload rejects.

Common situations: Filters over token types (e.g. collecting all comment or string tokens) written against the wrong overload's semantics; code migrated from get(start, stop) that relied on null returns for invalid ranges; highlighting code that clamps indices incorrectly.

Related errors


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