quarkusio/quarkus · error · PanacheQueryException
No suitable projection constructor found for ${type.getName(
Error message
No suitable projection constructor found for ${type.getName()}. Projection DTOs require a constructor with at least one parameter. What it means
ProjectionConstructorUtil.getProjectionConstructor throws this when every constructor of the projection DTO has zero parameters, i.e. the type has no constructor with at least one argument. Panache DTO projections are built by calling a constructor with the selected columns as arguments, so a parameterless-only DTO cannot be used for projection.
Source
Thrown at extensions/panache/panache-hibernate-common/runtime/src/main/java/io/quarkus/panache/hibernate/common/runtime/ProjectionConstructorUtil.java:100
if (!usableConstructors.isEmpty()) {
Constructor<?> selectedConstructor = null;
int minParameterCount = Integer.MAX_VALUE;
for (Constructor<?> constructor : usableConstructors) {
int parameterCount = getProjectionParameters(constructor).size();
if (parameterCount < minParameterCount) {
minParameterCount = parameterCount;
selectedConstructor = constructor;
}
}
return selectedConstructor;
}
for (Constructor<?> constructor : constructors) {
if (constructor.getParameterCount() > 0) {
throw new PanacheQueryException(buildNoSuitableConstructorMessage(type, constructor));
}
}
throw new PanacheQueryException("No suitable projection constructor found for " + type.getName()
+ ". Projection DTOs require a constructor with at least one parameter.");
}
public static String getProjectionParameterName(Class<?> parentType, String parentParameter, Parameter parameter,
BiFunction<Class<?>, String, String> nestedProjectionBuilder) {
String parameterName;
if (hasProjectedFieldName(parameter)) {
parameterName = getNameFromProjectedFieldName(parameter);
} else if (!parameter.isNamePresent()) {
throw new PanacheQueryException(
"Your application must be built with parameter names, this should be the default if"
+ " using Quarkus project generation. Check the Maven or Gradle compiler configuration to include '-parameters'."
+ " When using Kotlin data classes with value classes or default parameters, Panache skips synthetic"
+ " constructors automatically; if this error persists, annotate the constructor with @ProjectedConstructor"
+ " or annotate parameters with @ProjectedFieldName.");
} else {
try {
Field field = parentType.getDeclaredField(parameter.getName());View on GitHub (pinned to e1c734241f)
Solutions
- Add a constructor with at least one parameter matching the select items, e.g. public MyDto(String name)
- Alternatively convert the DTO to a Java record whose canonical constructor serves as the projection constructor
- If using Lombok, ensure @AllArgsConstructor (or an explicit constructor) is generated and -parameters is enabled
- Map fields manually instead by selecting into the entity and converting after the query
Example fix
// before
public class PersonDto {
private String name;
public String getName() { return name; }
}
// after
public record PersonDto(String name) {} Defensive patterns
Strategy: validation
Validate before calling
static void assertHasParameterizedConstructor(Class<?> dto) {
if (java.util.Arrays.stream(dto.getConstructors()).allMatch(c -> c.getParameterCount() == 0)) {
throw new IllegalStateException(dto.getName() + " cannot be used as a projection: no constructor with parameters");
}
} Type guard
boolean isUsableProjection(Class<?> dto) {
return java.util.Arrays.stream(dto.getConstructors())
.anyMatch(c -> c.getParameterCount() > 0);
} Try / catch
try {
return repo.findAll().project(Dto.class).list();
} catch (PanacheQueryException e) {
throw new IllegalStateException("DTO " + Dto.class.getSimpleName() + " lacks a projection constructor", e);
} Prevention
- Prefer records or explicit all-args constructors for projection DTOs
- Don't reuse JavaBean-style setter-only DTOs for Panache projections
- With Lombok, include @AllArgsConstructor and compile with -parameters
- Review DTOs used with .project(...) during refactors that remove constructors
When it happens
Trigger: Calling PanacheQuery.project(SomeDto.class) where SomeDto only declares a no-arg constructor (default constructor, or a class with no explicit constructors at all).
Common situations: JavaBean-style DTO designed for setter binding reused as a Panache projection; records are fine but plain classes with only default constructors are not; forgetting that projection requires constructor mapping unlike Hibernate bean mapping.
Related errors
- No suitable projection constructor found for ${type.getName(
- Your application must be built with parameter names, this sh
- The annotation ProjectedFieldName must have a non-empty valu
- Unable to read ProjectedFieldName value
- Missing ProjectedFieldName annotation
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/4283132df4905a88.
Report an issue: GitHub.