antlr/antlr4 · error · Error
replace op boundaries of ${rop} overlap with previous ${prev
Error message
replace op boundaries of ${rop} overlap with previous ${prevRop} What it means
Thrown by IntervalSet.remove(int) when the set has been marked read-only with setReadonly(true). Read-only sets are shared across ATN instances and parsers; removing an element would silently change lexer/parser behavior everywhere the set is shared, so removal is rejected.
Source
Thrown at runtime/JavaScript/src/antlr4/TokenStreamRewriter.js:259
let prevReplaces = this.getKindOfOps(rewrites, ReplaceOp, i);
for (let prevRop of prevReplaces) {
if (prevRop.index >= rop.index && prevRop.lastIndex <= rop.lastIndex) {
// delete replace as it's a no-op.
rewrites[prevRop.instructionIndex] = undefined;
continue;
}
// throw exception unless disjoint or identical
let disjoint =
prevRop.lastIndex < rop.index || prevRop.index > rop.lastIndex;
// Delete special case of replace (text==null):
// D.i-j.u D.x-y.v | boundaries overlap combine to max(min)..max(right)
if (prevRop.text == null && rop.text == null && !disjoint) {
rewrites[prevRop.instructionIndex] = undefined; // kill first delete
rop.index = Math.min(prevRop.index, rop.index);
rop.lastIndex = Math.max(prevRop.lastIndex, rop.lastIndex);
}
else if (!disjoint) {
throw new Error(`replace op boundaries of ${rop} overlap with previous ${prevRop}`);
}
}
}
// WALK INSERTS
for (let i = 0; i < rewrites.length; i++) {
let op = rewrites[i];
if (op == null) {
continue;
}
if (!(op instanceof InsertBeforeOp)) {
continue;
}
let iop = op;
// combine current insert with prior if any at same index
let prevInserts = this.getKindOfOps(rewrites, InsertBeforeOp, i);
for (let prevIop of prevInserts) {
if (prevIop.index === iop.index) {View on GitHub (pinned to 7d5770395b)
Solutions
- Copy then remove: IntervalSet copy = new IntervalSet(shared); copy.remove(el);
- Check isReadonly() before removal and route to the copy path.
- Build a fresh set containing exactly the elements you want rather than subtracting from a shared one.
Example fix
// before
sharedSet.remove('
'); // IllegalStateException
// after
IntervalSet filtered = new IntervalSet(sharedSet);
filtered.remove('
'); Defensive patterns
Strategy: validation
Validate before calling
IntervalSet target = set.isReadonly() ? new IntervalSet(set) : set; target.remove(el);
Type guard
boolean isMutable(IntervalSet s) { return !s.isReadonly(); } Prevention
- Never remove from ATN-owned or cached sets; copy first.
- Build filtered sets from scratch instead of subtracting from shared ones.
- Check isReadonly() in debug builds to catch bad mutation sites early.
When it happens
Trigger: Calling remove(el) on a set obtained from ATN transitions, statically cached sets, or any set after setReadonly(true) was invoked.
Common situations: Tools that filter character classes or token types out of ATN-derived interval sets; refactoring code that used to own its set but now receives a shared one from the runtime.
Related errors
- insert op ${iop} within boundaries of previous ${rop}
- should only be one op per index
- index cannot be negative
- missing interface implementation
- Fatal error occured while evaluating the names of the gramma
AI-assisted analysis of antlr/antlr4@7d5770395b (2026-08-14).
Data as JSON: /api/errors/e85268fd8df3c9b1.
Report an issue: GitHub.