antlr/antlr4 · error · IllegalArgumentException
replace: range invalid: {from}..{to}(size={size})
Error message
replace: range invalid: {from}..{to}(size={size}) What it means
TokenStreamRewriter.replace(programName, from, to, text) validates the token index range before queueing a ReplaceOp. It rejects from > to, from < 0, to < 0, and to >= tokens.size(), because the rewriter can only replace tokens that actually exist in the stream. The message reports the offending range and the stream size.
Source
Thrown at runtime/Java/src/org/antlr/v4/runtime/TokenStreamRewriter.java:287
public void replace(int index, Object text) {
replace(DEFAULT_PROGRAM_NAME, index, index, text);
}
public void replace(int from, int to, Object text) {
replace(DEFAULT_PROGRAM_NAME, from, to, text);
}
public void replace(Token indexT, Object text) {
replace(DEFAULT_PROGRAM_NAME, indexT, indexT, text);
}
public void replace(Token from, Token to, Object text) {
replace(DEFAULT_PROGRAM_NAME, from, to, text);
}
public void replace(String programName, int from, int to, Object text) {
if ( from > to || from<0 || to<0 || to >= tokens.size() ) {
throw new IllegalArgumentException("replace: range invalid: "+from+".."+to+"(size="+tokens.size()+")");
}
RewriteOperation op = new ReplaceOp(from, to, text);
List<RewriteOperation> rewrites = getProgram(programName);
op.instructionIndex = rewrites.size();
rewrites.add(op);
}
public void replace(String programName, Token from, Token to, Object text) {
replace(programName,
from.getTokenIndex(),
to.getTokenIndex(),
text);
}
public void delete(int index) {
delete(DEFAULT_PROGRAM_NAME, index, index);
}
View on GitHub (pinned to 7d5770395b)
Solutions
- Clamp and order the range before calling: from = Math.max(0, Math.min(from, to)); to = Math.min(to, tokens.size() - 1)
- Derive indexes from tokens of the same stream via token.getTokenIndex() instead of computing them manually
- Check for EOF/sentinel tokens (getTokenIndex() < 0) before rewriting them
Example fix
// before rewriter.replace(ctx.start.getTokenIndex(), tokens.size(), "x"); // to >= size -> throws // after int from = Math.max(0, ctx.start.getTokenIndex()); int to = Math.min(ctx.stop.getTokenIndex(), tokens.size() - 1); rewriter.replace(from, to, "x");
Defensive patterns
Strategy: validation
Validate before calling
int size = tokens.size();
if (from < 0 || to < from || to >= size) {
throw new IllegalArgumentException("bad replace range " + from + ".." + to + " size=" + size);
}
rewriter.replace(from, to, text); Try / catch
try { rewriter.replace(from, to, text); }
catch (IllegalArgumentException e) { /* log range, skip or clamp and retry once with corrected bounds */ } Prevention
- Always derive from/to from token.getTokenIndex() of the same stream
- Remember the last valid index is tokens.size() - 1
- Reject sentinel/EOF tokens (negative index) before rewriting
When it happens
Trigger: replace(from, to, ...) with from greater than to (inverted arguments); to >= tokens.size() (e.g., tokens.size() instead of tokens.size()-1); negative indexes from sentinel tokens (EOF token index can be -1) passed via from.getTokenIndex(); replace(Token indexT, text) where the token belongs to a different stream.
Common situations: Off-by-one when computing the last token index; using ctx.stop.getTokenIndex()+1 assuming another token exists; mixing tokens from a different TokenStream; EOF token (index -1) passed as the from argument.
Related errors
- replace: range invalid: {}..{}(size={})
- index cannot be negative
- ANTLR 4 caught {} build errors.
- cannot consume EOF
- The ATN must be a lexer ATN.
AI-assisted analysis of antlr/antlr4@7d5770395b (2026-08-14).
Data as JSON: /api/errors/6b317ef9a68635d2.
Report an issue: GitHub.