quarkusio/quarkus · error · IllegalArgumentException
${method} of Repository ${repository} can only use interface
Error message
${method} of Repository ${repository} can only use interfaces to map results to non-entity types. What it means
When a derived query's return type is not the entity type, Quarkus's spring-data-jpa extension maps results into that type at build time by generating an implementation — but only if the type is an interface (an interface projection backed by entity getters). Returning a concrete non-entity class cannot be supported by generated bytecode, so the build fails with this IllegalArgumentException.
Source
Thrown at extensions/spring-data-jpa/deployment/src/main/java/io/quarkus/spring/data/deployment/generate/DerivedMethodsAdder.java:276
customResultTypeName = resultType.name();
if (customResultTypeName.equals(entityClassInfo.name())
|| isHibernateSupportedReturnType(customResultTypeName)) {
// no special handling needed
customResultTypeName = null;
} else {
// If the custom type is an interface, we need to generate the implementation
ClassInfo resultClassInfo = index.getClassByName(customResultTypeName);
if (Modifier.isInterface(resultClassInfo.flags())) {
// Find the implementation name, and use that for subsequent query result generation
customResultTypeName = customResultTypeImplNames.computeIfAbsent(customResultTypeName,
k -> createSimpleInterfaceImpl(k, entityClassInfo.name()));
// Remember the parameters for this usage of the custom type, we'll deal with it later
customResultTypes.computeIfAbsent(customResultTypeName,
k -> new ArrayList<>()).add(method.name());
} else {
throw new IllegalArgumentException(
method.name() + " of Repository " + repositoryClassInfo
+ " can only use interfaces to map results to non-entity types.");
}
}
}
DotName effectiveReturnTypeName = finalReturnType.kind() == Type.Kind.TYPE_VARIABLE ? DotNames.OBJECT
: finalReturnType.name();
generateFindQueryResultHandling(bc, panacheQuery, finalPageableParameterIndex, params,
repositoryClassInfo, entityClassInfo, effectiveReturnTypeName, parseResult.getTopCount(),
method.name(), customResultTypeName,
entityClassInfo.name().toString(), elementTypeToCast);
} else if (parseResult.getQueryType() == MethodNameParser.QueryType.COUNT) {
if (!DotNames.PRIMITIVE_LONG.equals(returnType.name())
&& !DotNames.LONG.equals(returnType.name())) {
throw new IllegalArgumentException(View on GitHub (pinned to e1c734241f)
Solutions
- Convert the DTO class to an interface with getters matching the entity's properties (interface projection)
- Use the entity type as the return type and map to a DTO manually in application code
- Use a @Query with a constructor/SELECT projection if a concrete class is really required
Example fix
// before
class PersonDto { private String name; public String getName() { return name; } }
PersonDto findByEmail(String email);
// after
interface PersonNameView { String getName(); }
PersonNameView findByEmail(String email); Defensive patterns
Strategy: validation
Validate before calling
// Ensure custom result types used in repository methods are interfaces
static void checkProjectionTypes(Class<?> repo) {
for (Method m : repo.getDeclaredMethods()) {
Class<?> r = m.getReturnType();
if (!r.isInterface() && !r.isAnnotationPresent(Entity.class) && !isBuiltIn(r))
throw new IllegalStateException(m.getName() + " returns non-interface non-entity " + r);
}
} Prevention
- Model projections as interfaces with getters matching entity properties
- Never return concrete DTO classes from derived query methods
- Name projection interfaces with a View/Projection suffix to make intent explicit
When it happens
Trigger: Declaring e.g. PersonDto findByEmail(String email) where PersonDto is a concrete class (not the entity Person and not an interface), inside a method whose query type is SELECT and whose custom result type is not an interface.
Common situations: Creating a DTO class with fields copied from the entity and using it directly as a return type; migrating from another framework (e.g. JPA constructor-expression queries) where class-based projections are allowed.
Related errors
- Method ${method} of interface ${interface} is not a getter m
- ${field} method does not exists in ${entity} class.
- ${method} of Repository ${repository} contains both a Sort p
- ${method} of Repository ${repository} is meant to be a count
- ${method} of Repository ${repository} is meant to be a count
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/efdfb60348c2c299.
Report an issue: GitHub.