gradle/gradle · error · UnsupportedOperationException

Cannot convert a Collection to type %s.

Error message

Cannot convert a Collection to type %s.

What it means

ProtocolToModelAdapter copies provider-side tooling model data into the client's view interfaces. CollectionMapper.createEmptyCollection can only instantiate ArrayList, LinkedHashSet, or TreeSet (plus DomainObjectSet); when the view interface's collection return type accepts none of those (Queue, Deque, Stack, a custom collection class), it throws UnsupportedOperationException naming the unsupported type.

Source

Thrown at platforms/ide/tooling-api/src/main/java/org/gradle/tooling/internal/adapter/CollectionMapper.java:43

import java.util.Map;
import java.util.TreeMap;
import java.util.TreeSet;

class CollectionMapper {
    Collection<Object> createEmptyCollection(Class<?> collectionType) {
        if (collectionType.equals(DomainObjectSet.class)) {
            return new ArrayList<Object>();
        }
        if (collectionType.isAssignableFrom(ArrayList.class)) {
            return new ArrayList<Object>();
        }
        if (collectionType.isAssignableFrom(LinkedHashSet.class)) {
            return new LinkedHashSet<Object>();
        }
        if (collectionType.isAssignableFrom(TreeSet.class)) {
            return new TreeSet<Object>();
        }
        throw new UnsupportedOperationException(String.format("Cannot convert a Collection to type %s.", collectionType.getName()));
    }

    Map<Object, Object> createEmptyMap(Class<?> mapType) {
        if (mapType.isAssignableFrom(LinkedHashMap.class)) {
            return new LinkedHashMap<Object, Object>();
        }
        if (mapType.isAssignableFrom(TreeMap.class)) {
            return new TreeMap<Object, Object>();
        }
        throw new UnsupportedOperationException(String.format("Cannot convert a Map to type %s.", mapType.getName()));
    }
}

View on GitHub (pinned to 534f27719b)

Solutions

  1. Change the model getter to List, Set, or SortedSet (the adapter maps these to ArrayList/LinkedHashSet/TreeSet)
  2. Fetch the standard type and convert client-side: new ArrayDeque<>(model.getHistory())
  3. Keep tooling model interfaces limited to JDK-standard collection abstractions

Example fix

// before
public interface MyToolingModel {
    Queue<String> getPendingOperations(); // adapter cannot build a Queue -> throws
}

// after
public interface MyToolingModel {
    List<String> getPendingOperations();
}
// client converts if needed: new ArrayDeque<>(model.getPendingOperations())
Defensive patterns

Strategy: validation

Validate before calling

// reject unsupported collection types before publishing a model interface
private static final Set<Class<?>> SUPPORTED = Set.of(
    Collection.class, List.class, Set.class, SortedSet.class, DomainObjectSet.class);

static void checkCollectionType(Class<?> type) {
    if (!SUPPORTED.contains(type)) {
        throw new IllegalArgumentException("Unsupported tooling-model collection type: " + type.getName());
    }
}

Type guard

static boolean isSupportedCollectionType(Class<?> type) {
    return Collection.class.equals(type) || List.class.equals(type) || Set.class.equals(type)
        || SortedSet.class.equals(type) || DomainObjectSet.class.equals(type);
}

Prevention

When it happens

Trigger: Declaring a custom tooling model interface with a getter returning an unsupported collection type, e.g. Queue<String> getHistory() or MyCustomList getItems(), then fetching that model from a ProjectConnection.

Common situations: Custom tooling models in plugins consumed by IDEs or CI where the author used an exotic collection type; refactor from List to a domain-specific collection class; model interfaces generated with strict types.

Related errors


AI-assisted analysis of gradle/gradle@534f27719b (2026-08-22). Data as JSON: /api/errors/57de66204eda8556. Report an issue: GitHub.