hibernate/hibernate-orm · error · ArrayIndexOutOfBoundsException
negative index
Error message
negative index
What it means
Thrown by PersistentList.get(int) when a negative index is passed to a Hibernate-managed List mapped as an entity collection. Hibernate checks the index up front (before readElementByIndex, which may hit the database on an uninitialized lazy collection) and throws ArrayIndexOutOfBoundsException with the message 'negative index', matching the contract of java.util.List. Any caller doing positional access on an @OneToMany/List attribute can hit it.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentList.java:304
@Override
public void clear() {
if ( isClearQueueEnabled() ) {
queueOperation( new Clear() );
}
else {
initialize( true );
if ( ! list.isEmpty() ) {
list.clear();
dirty();
}
}
}
@Override
public E get(int index) {
if ( index < 0 ) {
throw new ArrayIndexOutOfBoundsException( "negative index" );
}
return readElementByIndex( index ).evaluate( () -> list.get( index ) );
}
@Override
public E set(int index, E value) {
if (index<0) {
throw new ArrayIndexOutOfBoundsException("negative index");
}
if ( isPutQueueEnabled()
&& readElementByIndex( index ) instanceof Defined<E> element ) {
final E old = element.result();
queueOperation( new Set( index, value, old ) );
return old;
}
else {
write();
return list.set( index, value );View on GitHub (pinned to fad1729dce)
Solutions
- Validate index >= 0 (and index < size()) before calling get; reject with a domain-level error or clamp
- If the index comes from page/offset math, guard the inputs (page >= 1) before computing it
- Prefer iteration (for-each, streams) or Optional-returning finders over positional access on entity collections
- Wrap positional reads in one bounds-checked helper used everywhere instead of scattering raw get() calls
Example fix
// before
Item first = order.getItems().get(idx - 1); // idx == 0 -> -1
// after
int i = idx - 1;
List<Item> items = order.getItems();
if (i < 0 || i >= items.size()) {
throw new IllegalArgumentException("index out of range: " + i);
}
Item first = items.get(i); Defensive patterns
Strategy: validation
Validate before calling
List<Item> items = entity.getItems();
if (index < 0 || index >= items.size()) {
throw new IllegalArgumentException("index out of range: " + index + " for size " + items.size());
}
Item item = items.get(index); Try / catch
try {
Item item = entity.getItems().get(index);
} catch (IndexOutOfBoundsException e) {
throw new IllegalArgumentException("Invalid index " + index, e); // boundary translates, does not swallow
} Prevention
- Bounds-check every computed index (negative and >= size) before positional access
- Validate pagination inputs before converting them to offsets
- Prefer for-each/streams over manual index loops on entity collections
- Centralize positional reads in one checked helper
When it happens
Trigger: Calling entity.getItems().get(i) with i < 0: off-by-one index math on possibly-empty lists, (page-1)*size going negative for page 0, hand-rolled binary search returning -1, or loop bounds computed from another collection's size.
Common situations: Pagination/offset arithmetic that assumes a non-empty list; porting code that used a sentinel index; iterating with 'while (i > -1)' loops over lazy collections; UI input converted directly into an index.
Related errors
- queued clear cannot be used with orphan delete
- Sets don't have indexes
- cannot recreate collection while filter is enabled: " + coll
- cannot recreate collection while filter is enabled [%s : %s]
- null key for collection: %s
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/e86c829363b93cd2.
Report an issue: GitHub.