{"record":{"id":"41da40a269b394cc","repo":"flowable/flowable-engine","slug":"cannot-find-field-or-method-with-annotation-id-on","errorCode":null,"errorMessage":"Cannot find field or method with annotation @Id on class '${class}', only single-valued primary keys are supported on JPA-entities","messagePattern":"Cannot find field or method with annotation @Id on class '(.+?)', only single-valued primary keys are supported on JPA-entities","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/types/JPAEntityScanner.java","lineNumber":53,"sourceCode":"        while (clazz != null && !clazz.equals(Object.class)) {\n\n            // Class should have @Entity annotation\n            boolean isEntity = isEntityAnnotationPresent(clazz);\n\n            if (isEntity) {\n                metaData.setEntityClass(clazz);\n                metaData.setJPAEntity(true);\n                // Try to find a field annotated with @Id\n                Field idField = getIdField(clazz);\n                if (idField != null) {\n                    metaData.setIdField(idField);\n                } else {\n                    // Try to find a method annotated with @Id\n                    Method idMethod = getIdMethod(clazz);\n                    if (idMethod != null) {\n                        metaData.setIdMethod(idMethod);\n                    } else {\n                        throw new FlowableException(\"Cannot find field or method with annotation @Id on class '\" + clazz.getName() + \"', only single-valued primary keys are supported on JPA-entities\");\n                    }\n                }\n                break;\n            }\n            clazz = clazz.getSuperclass();\n        }\n        return metaData;\n    }\n\n    private Method getIdMethod(Class<?> clazz) {\n        Method idMethod = null;\n        // Get all public declared methods on the class. According to spec, @Id should only be\n        // applied to fields and property get methods\n        Method[] methods = clazz.getMethods();\n        Id idAnnotation = null;\n        for (Method method : methods) {\n            idAnnotation = method.getAnnotation(Id.class);\n            if (idAnnotation != null && !method.isBridge()) {","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/types/JPAEntityScanner.java#L35-L71","documentation":"JPAEntityScanner inspects a JPA entity class and its superclasses to locate the primary key, supporting only a single @Id-annotated field or getter. If neither exists (e.g. composite @EmbeddedId, @IdClass, or missing annotations), it throws this FlowableException.","triggerScenarios":"First time a JPA entity class is used as a Flowable variable: scanClass finds no @Id field and no @Id getter anywhere in the class hierarchy — entities with @EmbeddedId/@IdClass composite keys, or entities annotated only with e.g. @GeneratedValue without @Id.","commonSituations":"Composite primary key entities (very common in legacy schemas); entities relying on XML ORM mapping instead of annotations; typo where the getter lost its @Id annotation during refactoring.","solutions":["Give the entity a single @Id-annotated field or getter (annotations, not XML mapping — the scanner reads reflection annotations).","Replace composite keys (@EmbeddedId/@IdClass) with a single-valued synthetic key (e.g. String or Long surrogate key) if the entity must be used as a Flowable variable.","If you must keep the composite key, wrap the lookup in your own variable type or store the individual key columns as separate variables.","Upgrade check: confirm the class hierarchy chain — @Id must be on the class or a superclass reachable via getSuperclass(), not on an @MappedSuperclass outside the chain you expect."],"exampleFix":"// before\n@EmbeddedId\nprivate CustomerPk id; // composite -> throws\n// after\n@Id\n@GeneratedValue\nprivate Long id; // single-valued key","handlingStrategy":"validation","validationCode":"for (Class<?> c = entityClass; c != null; c = c.getSuperclass()) {\n  boolean hasId = Arrays.stream(c.getDeclaredFields()).anyMatch(f -> f.isAnnotationPresent(jakarta.persistence.Id.class))\n    || Arrays.stream(c.getDeclaredMethods()).anyMatch(m -> m.isAnnotationPresent(jakarta.persistence.Id.class));\n  if (hasId) return;\n}\nthrow new IllegalArgumentException(entityClass + \" has no single @Id field/getter\");","typeGuard":"boolean scannableEntity(Class<?> c) { return c.isAnnotationPresent(jakarta.persistence.Entity.class) && singleIdAnnotationCount(c) == 1; }","tryCatchPattern":"try { runtimeService.setVariable(executionId, \"entity\", jpaEntity); } catch (FlowableException e) { if (e.getMessage().contains(\"Cannot find field or method with annotation @Id\")) { throw new ConfigurationException(\"Use single-valued @Id entities with Flowable JPA variables\", e); } throw e; }","preventionTips":["Never use @EmbeddedId or @IdClass entities as Flowable JPA variables — use a surrogate single-valued key.","Rely on annotation-based mapping (not pure orm.xml) since the scanner uses reflection annotations.","Add a startup test that scans all entities eligible for variables for exactly one @Id member."],"tags":["jpa","primary-key","composite-key","class-scanning"],"backgroundTag":"unsupported-operation","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}