quarkusio/quarkus · error · IllegalArgumentException

The use of interfaces as the generic type of Lists fields /…

Error message

The use of interfaces as the generic type of Lists fields / methods is not allowed. Offending field is ' + member.name() + ' of class ' + member.declaringClass().name().toString() + '

What it means

YamlListObjectHandler resolves the concrete element class of a List<...> field/method so it can instantiate elements when binding YAML config. Interfaces cannot be instantiated, so validation rejects them outright with IllegalArgumentException.

Solutions

  1. Change the list element type from the interface to a concrete class with a public no-args constructor
  2. Introduce a concrete base/default implementation class and use List<Impl> in the config
  3. Move polymorphism out of the config binding (bind concrete class, expose interface separately)

Example fix

// before
List<Handler> handlers();
// after
List<DefaultHandler> handlers();
Defensive patterns

Strategy: type-guard

Validate before calling

static <T> void checkListElementType(List<T> listField, Class<?> cfg) {
    // element type must be a concrete class
}

Type guard

boolean isConcreteListElement(Type t) {
    return t instanceof Class<?> c && !c.isInterface() && !c.isAnnotation();
}

Try / catch

catch (IllegalArgumentException e) { if (e.getMessage().contains("not allowed")) { /* use concrete element class */ } throw e; }

Prevention

When it happens

Trigger: A @ConfigProperties class/interface (processed via quarkus-config-yaml list-of-object support) declares a field or method of type List<SomeInterface> where SomeInterface is an interface, not a class.

Common situations: Modeling config lists against an abstraction (List<Handler> where Handler is an interface) carried over from Spring Boot style configuration.

Related errors


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

Appendix: source

Thrown at extensions/spring-boot-properties/deployment/src/main/java/io/quarkus/spring/boot/properties/deployment/YamlListObjectHandler.java:201

                    mc.public_();
                    mc.body(b -> {
                        LocalVar resultHandle = b.localVar("resultHandle", b.new_(ConstructorDesc.of(HashMap.class)));
                        for (Map.Entry<String, String> entry : fieldNameMap.entrySet().stream()
                                .sorted(Map.Entry.comparingByKey()).toList()) {
                            b.invokeVirtual(
                                    MethodDesc.of(HashMap.class, "put", Object.class, Object.class, Object.class),
                                    resultHandle, Const.of(entry.getKey()), Const.of(entry.getValue()));
                        }
                        b.return_(resultHandle);
                    });
                });
            }
        });
    }

    private void validateClass(ClassInfo classInfo, Member member) {
        if (Modifier.isInterface(classInfo.flags())) {
            throw new IllegalArgumentException(
                    "The use of interfaces as the generic type of Lists fields / methods is not allowed. Offending field is '"
                            + member.name() + "' of class '" + member.declaringClass().name().toString() + "'");
        }
        if (!classInfo.hasNoArgsConstructor()) {
            throw new IllegalArgumentException(
                    String.format("Class '%s' which is used as %s in class '%s' must have a no-args constructor", classInfo,
                            member.phraseUsage(), member.declaringClass().name().toString()));
        }
        if (!Modifier.isPublic(classInfo.flags())) {
            throw new IllegalArgumentException(
                    String.format("Class '%s' which is used as %s in class '%s' must be a public class", classInfo,
                            member.phraseUsage(), member.declaringClass().name().toString()));
        }
    }

    private ClassInfo validateType(Type type) {
        if (type.kind() != Type.Kind.PARAMETERIZED_TYPE) {
            throw new IllegalArgumentException(ILLEGAL_ARGUMENT_MESSAGE);

View on GitHub (pinned to e1c734241f)