quarkusio/quarkus · error · IllegalArgumentException

parameterized type %s can not be inherited from by %s (or a

Error message

parameterized type %s can not be inherited from by %s (or a predecessor) with different type arguments.

What it means

During REST client build-time generation, Quarkus walks the interface hierarchy of a client interface to resolve generic type arguments. If the same parameterized interface appears twice in the hierarchy with different type arguments — which plain Java should prevent — the mapping cache detects a conflict and aborts. This usually indicates duplicate/conflicting versions of a library on the classpath or bytecode manipulated in ways Java's compiler would not produce.

Source

Thrown at extensions/resteasy-reactive/rest-client-jaxrs/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java:1565

    private void fillHierarchyIdentifierTypeLookupMap(IndexView index, ClassInfo owner,
            Map<DotName, Map<String, Type>> hierarchyIdentifierTypeLookupMap) {
        List<Type> interfaceTypes = owner.interfaceTypes();
        // no need to check for Object, not an interface
        if (!owner.isInterface() || interfaceTypes.isEmpty()) {
            return;
        }

        for (Type interfaceType : interfaceTypes) {
            Type resolvedInterfaceType = resolveType(interfaceType,
                    hierarchyIdentifierTypeLookupMap.getOrDefault(owner.name(), Collections.emptyMap()), null);

            Map<String, Type> identifierTypeLookupMap = determineIdentifierTypeLookupMap(index, resolvedInterfaceType);

            if (hierarchyIdentifierTypeLookupMap.putIfAbsent(interfaceType.name(), identifierTypeLookupMap) != null) {
                if (!hierarchyIdentifierTypeLookupMap.get(interfaceType.name()).equals(identifierTypeLookupMap)) {
                    // Just to be safe, java should prevent this. This could maybe happen with different versions of a library on the classpath?
                    throw new IllegalArgumentException(
                            "parameterized type %s can not be inherited from by %s (or a predecessor) with different type arguments."
                                    .formatted(interfaceType.name(), owner.name()));
                }
            }

            fillHierarchyIdentifierTypeLookupMap(index, index.getClassByName(interfaceType.name()),
                    hierarchyIdentifierTypeLookupMap);
        }
    }

    private Map<String, Type> determineIdentifierTypeLookupMap(IndexView index, Type type) {
        Map<String, Type> result = new HashMap<>();
        if (type.kind() == PARAMETERIZED_TYPE) {
            ClassInfo classInfo = index.getClassByName(type.name());
            ParameterizedType parameterizedType = type.asParameterizedType();

            for (int i = 0; i < parameterizedType.arguments().size(); i++) {
                // No need to check if the class even has type parameters, if the type has an argument for it, then the class must have a type parameter for it

View on GitHub (pinned to e1c734241f)

Solutions

  1. Run mvn dependency:tree and resolve duplicate/conflicting versions of the library owning the interface with dependencyManagement or exclusions
  2. Clean and rebuild (mvn clean install) to remove stale generated/indexed classes
  3. Ensure the generic interface hierarchy is consistent in source — a single type argument per interface across all subtypes
  4. If caused by a generated sub-resource, regenerate/refresh annotation-indexed sources

Example fix

// before (pom.xml mixed versions)
<dependency><groupId>com.example</groupId><artifactId>api-lib</artifactId><version>1.0</version></dependency>
<dependency><groupId>com.example</groupId><artifactId>api-lib</artifactId><version>2.0</version></dependency>
// after
<dependencyManagement>
  <dependencies>
    <dependency><groupId>com.example</groupId><artifactId>api-lib</artifactId><version>2.0</version></dependency>
  </dependencies>
</dependencyManagement>
Defensive patterns

Strategy: validation

Validate before calling

// Before building, check dependency conflicts:
// mvn dependency:tree -Dincludes=com.example:api-lib
// Ensure only one version of the library defining the generic interface exists.
Set<String> versions = new LinkedHashSet<>();
ClassLoader cl = Thread.currentThread().getContextClassLoader();
// verify a single consistent jar provides the interface:
String res = "com/example/Repo.class";
try (InputStream in = cl.getResourceAsStream(res)) {
    if (in == null) throw new IllegalStateException("interface missing from classpath");
}

Prevention

When it happens

Trigger: A client interface (or its superinterfaces) inherits the same generic interface through two paths with different type parameters, e.g. via different library versions providing classes like Foo extends Repo<String> and Repo<Integer> for the same interface name.

Common situations: Mixed versions of a library on the classpath after a dependency upgrade; shaded/relocated jars redefining the same DotName; build-time vs runtime classpath mismatch in fast-jar; generated sub-resource interfaces conflicting with hand-written ones.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/e6b864fee4948881. Report an issue: GitHub.