elastic/elasticsearch · error · UnsupportedOperationException
${className} does not support retainAll()
Error message
${className} does not support retainAll() What it means
LazyPropertyList overrides List.retainAll(Collection) to throw UnsupportedOperationException. retainAll is the complement of removeAll and would force eager evaluation of every lazy supplier to compute the intersection, defeating the deferred-evaluation design. clear() is supported as a full reset.
Source
Thrown at build-tools/src/main/java/org/elasticsearch/gradle/LazyPropertyList.java:108
}
@Override
public boolean addAll(int index, Collection<? extends T> c) {
int i = index;
for (T item : c) {
this.add(i++, item);
}
return true;
}
@Override
public boolean removeAll(Collection<?> c) {
throw new UnsupportedOperationException(this.getClass().getName() + " does not support removeAll()");
}
@Override
public boolean retainAll(Collection<?> c) {
throw new UnsupportedOperationException(this.getClass().getName() + " does not support retainAll()");
}
@Override
public void clear() {
delegate.clear();
}
@Override
public T get(int index) {
PropertyListEntry<T> entry = delegate.get(index);
validate(entry);
return entry.getValue();
}
@Override
public T set(int index, T element) {
return delegate.set(index, new PropertyListEntry<>(() -> element, PropertyNormalization.DEFAULT)).getValue();
}View on GitHub (pinned to db6a809a66)
Solutions
- Compute the retained subset into a new list, clear(), then re-add: lazyList.clear(); kept.forEach(lazyList::add).
- Move the retainAll logic upstream so the LazyPropertyList only ever receives its final contents.
- If intersection semantics are essential, maintain a plain List<T> alongside and sync on build.
Example fix
// before lazyList.retainAll(allowed); // UnsupportedOperationException // after List<T> kept = lazyList.stream().filter(allowed::contains).toList(); lazyList.clear(); kept.forEach(lazyList::add);
Defensive patterns
Strategy: validation
Validate before calling
if (list instanceof LazyPropertyList) {
throw new IllegalStateException("retainAll() not supported on LazyPropertyList");
} Type guard
static boolean isLazyPropertyList(List<?> l) { return l instanceof LazyPropertyList; } Try / catch
try { list.retainAll(c); } catch (UnsupportedOperationException e) { /* rebuild: intersect and clear+addAll */ } Prevention
- Compute retained entries into a new list, clear, then re-add.
- Move intersection logic upstream of the LazyPropertyList.
- Prefer filtering at the provider/ListProperty level for Gradle tasks.
When it happens
Trigger: Calling .retainAll(Collection) on a LazyPropertyList. Surfaces when intersecting lists, deduplicating against an allow-list, or using collection frameworks that invoke retainAll for filtering.
Common situations: Migrating intersection/dedup logic from ArrayList to LazyPropertyList; Gradle task code that narrows a configured list to a subset at configuration time.
Related errors
- ${className} does not support remove()
- ${className} does not support removeAll()
- ${className} does not support putAll()
- platform cannot be set on elasticsearch distribution [${name
- bundledJdk cannot be set on elasticsearch distribution [${na
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/efcabef589dbb627.
Report an issue: GitHub.