{"record":{"id":"82e162797e39f3a9","repo":"quarkusio/quarkus","slug":"missing-projectedfieldname-annotation","errorCode":null,"errorMessage":"Missing ProjectedFieldName annotation","messagePattern":"Missing ProjectedFieldName annotation","errorType":"exception","errorClass":"PanacheQueryException","httpStatus":null,"severity":"error","filePath":"extensions/panache/panache-hibernate-common/runtime/src/main/java/io/quarkus/panache/hibernate/common/runtime/ProjectionConstructorUtil.java","lineNumber":216,"sourceCode":"        }\n        return false;\n    }\n\n    private static String getNameFromProjectedFieldName(AnnotatedElement annotatedElement) {\n        for (java.lang.annotation.Annotation annotation : annotatedElement.getAnnotations()) {\n            if (PROJECTED_FIELD_NAME_ANNOTATIONS.contains(annotation.annotationType().getName())) {\n                try {\n                    String name = (String) annotation.annotationType().getMethod(\"value\").invoke(annotation);\n                    if (name.isEmpty()) {\n                        throw new PanacheQueryException(\"The annotation ProjectedFieldName must have a non-empty value.\");\n                    }\n                    return name;\n                } catch (ReflectiveOperationException e) {\n                    throw new PanacheQueryException(\"Unable to read ProjectedFieldName value\", e);\n                }\n            }\n        }\n        throw new PanacheQueryException(\"Missing ProjectedFieldName annotation\");\n    }\n\n    private static String buildNoSuitableConstructorMessage(Class<?> type, Constructor<?> rejected) {\n        StringBuilder message = new StringBuilder(\"No suitable projection constructor found for \")\n                .append(type.getName())\n                .append(\" (rejected constructor: \")\n                .append(rejected)\n                .append(\").\");\n        if (isKotlinClass(type)) {\n            message.append(\" Kotlin value classes and default parameters may produce synthetic constructors.\")\n                    .append(\" Use @ProjectedConstructor, @ProjectedFieldName, or a DTO with plain property types such as Long.\");\n        } else {\n            message.append(\" Use @ProjectedConstructor or @ProjectedFieldName to select a usable constructor,\")\n                    .append(\" and ensure the application is built with parameter names (-parameters).\");\n        }\n        return message.toString();\n    }\n","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/panache/panache-hibernate-common/runtime/src/main/java/io/quarkus/panache/hibernate/common/runtime/ProjectionConstructorUtil.java#L198-L234","documentation":"getNameFromProjectedFieldName iterates a parameter's annotations looking for one whose type name is in PROJECTED_FIELD_NAME_ANNOTATIONS; if none is found it throws PanacheQueryException(\"Missing ProjectedFieldName annotation\"). This indicates Panache needed an explicit field-name mapping (typically because parameter names are not compiled in) but the required annotation was absent on that parameter.","triggerScenarios":"A constructor parameter without @ProjectedFieldName reaching the name-resolution path where reflection cannot supply a name — i.e. class compiled without -parameters and no other name source, so the fallback demands the annotation and fails when missing.","commonSituations":"Annotating only some constructor parameters and missing one; applying the annotation to fields instead of constructor parameters; classpath mismatch where an old compiled DTO lacks both -parameters and annotations.","solutions":["Annotate every constructor parameter with @ProjectedFieldName(\"entityFieldName\")","Rebuild the application with -parameters so annotations are not strictly required","Ensure annotations are placed on constructor parameters, not class fields","Rebuild all modules of the DTO after adding annotations (stale classes keep the error)"],"exampleFix":"// before\npublic PersonDto(String name, @ProjectedFieldName(\"age\") int years) { ... }\n\n// after\npublic PersonDto(@ProjectedFieldName(\"name\") String name, @ProjectedFieldName(\"age\") int years) { ... }","handlingStrategy":"validation","validationCode":"static void assertAllParametersAnnotated(java.lang.reflect.Constructor<?> c) {\n    for (java.lang.reflect.Parameter p : c.getParameters()) {\n        if (!p.isNamePresent() && !p.isAnnotationPresent(ProjectedFieldName.class)) {\n            throw new IllegalStateException(\"Parameter \" + p + \" needs @ProjectedFieldName or compile with -parameters\");\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    return query.project(Dto.class).list();\n} catch (PanacheQueryException e) {\n    if (e.getMessage().contains(\"Missing ProjectedFieldName\")) {\n        throw new IllegalStateException(\"Annotate all parameters of \" + Dto.class + \" constructor\", e);\n    }\n    throw e;\n}","preventionTips":["When adding @ProjectedFieldName, annotate every constructor parameter, not just some","Rebuild the whole project after adding annotations so stale classes don't linger","Enable -parameters as the primary mechanism and use annotations only where names differ","Put annotations on constructor parameters, not on fields"],"tags":["panache","jpa","annotation","projection","reflection"],"backgroundTag":"missing-annotation","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}