quarkusio/quarkus · error · PanacheQueryException

No suitable projection constructor found for ${type.getName(

Error message

No suitable projection constructor found for ${type.getName()} (rejected constructor: ${constructor}).

What it means

ProjectionConstructorUtil.getProjectionConstructor resolves the constructor used for DTO projections in Panache queries. When no constructor matching the selected parameters exists, it throws a message naming the type and the rejected constructor via buildNoSuitableConstructorMessage. Panache matches projection constructors against the query select items (by parameter count/names), so a DTO whose constructors all mismatch the select list triggers this error.

Source

Thrown at extensions/panache/panache-hibernate-common/runtime/src/main/java/io/quarkus/panache/hibernate/common/runtime/ProjectionConstructorUtil.java:97

            }
        }

        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.");

View on GitHub (pinned to e1c734241f)

Solutions

  1. Add a constructor to the DTO whose parameters match the select items in order and type (e.g. PersonName(String name, int age))
  2. Compile with -parameters so constructor parameter names are available for matching
  3. Annotate constructor parameters with @ProjectedFieldName("fieldName") to map them explicitly when names differ
  4. Annotate the intended constructor with @ProjectedConstructor if multiple constructors exist
  5. Verify the query select list (select foo.bar, foo.baz) matches the DTO constructor parameter count/types

Example fix

// before
public class PersonName {
    public String name;
}

// after
public class PersonName {
    public PersonName(String name) { this.name = name; }
}
Defensive patterns

Strategy: validation

Validate before calling

// verify at startup that the DTO has a usable projection constructor
static void assertProjectionDto(Class<?> dto) {
    boolean ok = java.util.Arrays.stream(dto.getConstructors())
        .anyMatch(c -> c.getParameterCount() > 0);
    if (!ok) throw new IllegalStateException(dto + " needs a constructor with parameters for projection");
}

Try / catch

try (PanacheQuery<Entity> q = repo.findAll().project(Dto.class)) {
    return q.list();
} catch (PanacheQueryException e) {
    log.error("Projection constructor mismatch for DTO; check select list vs constructor", e);
    throw e;
}

Prevention

When it happens

Trigger: Using query.project(Class) with a DTO that has no constructor whose parameter list matches the select items; the single-parameter constructor examined was rejected (wrong type or name mismatch) so Panache reports it as rejected; multiple candidate constructors where none align with the projection columns.

Common situations: DTO with only a no-arg constructor plus setters (Panache projections need constructor-based mapping); DTO constructor parameter names not compiled in (missing -parameters) so matching by name fails; changed select list without updating the DTO constructor; Lombok @AllArgsConstructor with fields in a different order than the select items.

Related errors


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