oracle/graal · error · IndexOutOfBoundsException

Index: ${index}, Size: ${size}

Error message

Index: ${index}, Size: ${size}

What it means

IndexOutOfBoundsException with message 'Index: N, Size: S', thrown by AbstractListWithoutField.rangeCheckForAdd when an insertion index is negative or greater than the list size. Valid insertion points for add are 0..size inclusive; anything else is rejected.

Source

Thrown at espresso/src/com.oracle.truffle.espresso.polyglot/src/com/oracle/truffle/espresso/polyglot/collections/AbstractListWithoutField.java:539

     * @implSpec This implementation gets a list iterator positioned before {@code fromIndex}, and
     *           repeatedly calls {@code ListIterator.next} followed by {@code ListIterator.remove}
     *           until the entire range has been removed. <b>Note: if {@code ListIterator.remove}
     *           requires linear time, this implementation requires quadratic time.</b>
     *
     * @param fromIndex index of first element to be removed
     * @param toIndex index after last element to be removed
     */
    protected void removeRange(int fromIndex, int toIndex) {
        ListIterator<E> it = listIterator(fromIndex);
        for (int i = 0, n = toIndex - fromIndex; i < n; i++) {
            it.next();
            it.remove();
        }
    }

    private void rangeCheckForAdd(int index) {
        if (index < 0 || index > size()) {
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }
    }

    private String outOfBoundsMsg(int index) {
        return "Index: " + index + ", Size: " + size();
    }

    private static class SubList<E> extends AbstractListWithoutField<E> {
        private final AbstractListWithoutField<E> root;
        private final SubList<E> parent;
        private final int offset;
        protected int size;

        /**
         * Constructs a sublist of an arbitrary AbstractList, which is not a SubList itself.
         */
        SubList(AbstractListWithoutField<E> root, int fromIndex, int toIndex) {
            this.root = root;

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Check 0 <= index <= list.size() before the add/iterator call.
  2. Treat -1 from indexOf/lastIndexOf as 'not found' and skip the insert.
  3. Recompute size immediately before inserting when other threads mutate the list.
  4. Catch IndexOutOfBoundsException at user-input boundaries and report a validation error.

Example fix

// before
list.add(position, element); // position may be -1 from a failed search

// after
int position = list.indexOf(key);
if (position >= 0) {
    list.add(position, element);
}
Defensive patterns

Strategy: validation

Validate before calling

if (index < 0 || index > list.size()) {
    throw new IndexOutOfBoundsException("index " + index + " not in [0, " + list.size() + "]");
}

Try / catch

try {
    list.add(index, element);
} catch (IndexOutOfBoundsException e) {
    // report validation error to caller; do not silently retry with stale index
}

Prevention

When it happens

Trigger: Calling listIterator(index) or add(index, element) on the outer AbstractListWithoutField with index < 0 or index > size(); using an index returned by a failed search (-1); iterating with a cursor that ran past the end.

Common situations: Inserting at indexOf result without a found-check; concurrent shrink of the list between size() and add(); passing a cursor from a different list instance.

Related errors


AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14). Data as JSON: /api/errors/31ad2cbedb6f6c75. Report an issue: GitHub.