antlr/antlr4 · error · IllegalArgumentException

replace: range invalid

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.

Solutions

  1. Clamp and order the range before calling: from = Math.max(0, Math.min(from, to)); to = Math.min(to, tokens.size() - 1)
  2. Derive indexes from tokens of the same stream via token.getTokenIndex() instead of computing them manually
  3. 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

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


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

Appendix: 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)