quarkusio/quarkus · error · PanacheQueryException

Unable to read ProjectedFieldName value

Error message

Unable to read ProjectedFieldName value

What it means

getNameFromProjectedFieldName invokes the annotation's value() method reflectively; any ReflectiveOperationException (missing value method, inaccessible method, InvocationTargetException) is wrapped and rethrown as PanacheQueryException("Unable to read ProjectedFieldName value", e). Panache expects the annotation to follow the standard single String value() shape.

Source

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

        for (java.lang.annotation.Annotation annotation : annotatedElement.getAnnotations()) {
            if (annotationTypeName.equals(annotation.annotationType().getName())) {
                return true;
            }
        }
        return false;
    }

    private static String getNameFromProjectedFieldName(AnnotatedElement annotatedElement) {
        for (java.lang.annotation.Annotation annotation : annotatedElement.getAnnotations()) {
            if (PROJECTED_FIELD_NAME_ANNOTATIONS.contains(annotation.annotationType().getName())) {
                try {
                    String name = (String) annotation.annotationType().getMethod("value").invoke(annotation);
                    if (name.isEmpty()) {
                        throw new PanacheQueryException("The annotation ProjectedFieldName must have a non-empty value.");
                    }
                    return name;
                } catch (ReflectiveOperationException e) {
                    throw new PanacheQueryException("Unable to read ProjectedFieldName value", e);
                }
            }
        }
        throw new PanacheQueryException("Missing ProjectedFieldName annotation");
    }

    private static String buildNoSuitableConstructorMessage(Class<?> type, Constructor<?> rejected) {
        StringBuilder message = new StringBuilder("No suitable projection constructor found for ")
                .append(type.getName())
                .append(" (rejected constructor: ")
                .append(rejected)
                .append(").");
        if (isKotlinClass(type)) {
            message.append(" Kotlin value classes and default parameters may produce synthetic constructors.")
                    .append(" Use @ProjectedConstructor, @ProjectedFieldName, or a DTO with plain property types such as Long.");
        } else {
            message.append(" Use @ProjectedConstructor or @ProjectedFieldName to select a usable constructor,")
                    .append(" and ensure the application is built with parameter names (-parameters).");

View on GitHub (pinned to e1c734241f)

Solutions

  1. Use the standard io.quarkus.runtime.annotations.ProjectedFieldName annotation with a String value()
  2. If using a custom annotation, ensure it declares public String value()
  3. Check the cause (getCause) of the PanacheQueryException for the underlying reflective error
  4. Avoid custom annotation indirection on projection constructors

Example fix

// before
public @interface FieldName { String name(); } // no value() method

// after
public @interface FieldName { String value(); }
Defensive patterns

Strategy: try-catch

Validate before calling

for (java.lang.annotation.Annotation a : param.getAnnotations()) {
    try {
        a.annotationType().getMethod("value");
    } catch (NoSuchMethodException e) {
        throw new IllegalStateException("Annotation " + a + " lacks a value() method");
    }
}

Try / catch

try {
    return query.project(Dto.class).list();
} catch (PanacheQueryException e) {
    if (e.getMessage().equals("Unable to read ProjectedFieldName value") && e.getCause() != null) {
        log.error("Bad annotation shape: {}", e.getCause().toString());
    }
    throw e;
}

Prevention

When it happens

Trigger: Using an annotation matching a PROJECTED_FIELD_NAME_ANNOTATIONS name whose value() method is absent, non-String-returning, not accessible, or throws when invoked (e.g. a custom annotation with Class or array value).

Common situations: Custom meta-annotation mimicking ProjectedFieldName but with a different attribute signature; annotation on a class loaded by a restricted classloader in native mode; exotic annotation types with non-standard members.

Related errors


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