gradle/gradle · error · UnsupportedOperationException
Cannot add '%s' to '%s' as it is a filtered collection
Error message
Cannot add '%s' to '%s' as it is a filtered collection
What it means
Resolution must happen while the owning project's state is exclusively locked. resolveGraphIfRequired checks hasMutableState() on the project model and throws IllegalResolutionException when resolution is attempted without that lock, because the graph could be mutated concurrently underneath the resolver.
Source
Thrown at platforms/core-configuration/domain-object-collections/src/main/java/org/gradle/api/internal/collections/FilteredIndexedElementSource.java:30
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.gradle.api.internal.collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
// TODO make this work with pending elements
public class FilteredIndexedElementSource<T, S extends T> extends FilteredElementSource<T, S> implements IndexedElementSource<S> {
public FilteredIndexedElementSource(ElementSource<T> collection, CollectionFilter<S> filter) {
super(collection, filter);
}
@Override
public void add(int index, S element) {
throw new UnsupportedOperationException(String.format("Cannot add '%s' to '%s' as it is a filtered collection", element, this));
}
@Override
public S get(int index) {
int nextIndex = 0;
for (T t : collection) {
S s = filter.filter(t);
if (s != null) {
if (nextIndex == index) {
return s;
}
nextIndex++;
}
}
throw new IndexOutOfBoundsException();
}
@OverrideView on GitHub (pinned to 534f27719b)
Solutions
- Register the configuration as a task input (inputs.files(...)) so Gradle resolves it with proper locking and task dependencies
- Resolve only configurations of the project whose code is executing
- For cross-project data, consume artifacts/publications or task outputs instead of the other project's model
Example fix
// before
tasks.register('aggregate') {
doLast {
def files = project(':lib').configurations.runtimeClasspath.resolve() // IllegalResolutionException
}
}
// after
tasks.register('aggregate') {
def libCp = project(':lib').configurations.runtimeClasspath
inputs.files(libCp) // Gradle resolves up-front, with the lock and task dependencies
doLast { /* use the snapshot input files */ }
} Defensive patterns
Strategy: validation
Validate before calling
void safeResolve(Project current, Configuration c) {
if (!current.configurations.names.contains(c.name)) {
throw new GradleException('Cross-project resolution is unsafe; register the configuration as a task input instead')
}
c.resolve()
} Prevention
- Never call .resolve()/.files on another project's configuration
- Wire cross-project inputs via inputs.files so Gradle owns locking and task dependencies
- Keep resolution out of worker threads and doLast blocks
When it happens
Trigger: Resolving another project's configuration from a task or thread that does not own that project's lock: project(':lib').configurations.runtimeClasspath.resolve() inside a task of project A; resolving in background executors or worker threads; cross-project model queries during task execution.
Common situations: Custom tasks that reach into subproject configurations directly; migration to parallel execution or the configuration cache exposing previously hidden unsafe resolution; build logic resolving during doLast.
Related errors
- Cannot clear '%s' as it is a filtered collection
- Cannot open package '%s' in module '%s' defined in layer '%s
- Don't know how to serialize objects of type %s.
- Unexpected type tag %d found.
- Don't know how to serialize an object of type %s.
AI-assisted analysis of gradle/gradle@534f27719b (2026-08-22).
Data as JSON: /api/errors/6023bdee58975efd.
Report an issue: GitHub.