flowable/flowable-engine · error · FlowableException

Cannot find field or method with annotation @Id on class '${

Error message

Cannot find field or method with annotation @Id on class '${class}', only single-valued primary keys are supported on JPA-entities

What it means

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.

Source

Thrown at modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/types/JPAEntityScanner.java:53

        while (clazz != null && !clazz.equals(Object.class)) {

            // Class should have @Entity annotation
            boolean isEntity = isEntityAnnotationPresent(clazz);

            if (isEntity) {
                metaData.setEntityClass(clazz);
                metaData.setJPAEntity(true);
                // Try to find a field annotated with @Id
                Field idField = getIdField(clazz);
                if (idField != null) {
                    metaData.setIdField(idField);
                } else {
                    // Try to find a method annotated with @Id
                    Method idMethod = getIdMethod(clazz);
                    if (idMethod != null) {
                        metaData.setIdMethod(idMethod);
                    } else {
                        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");
                    }
                }
                break;
            }
            clazz = clazz.getSuperclass();
        }
        return metaData;
    }

    private Method getIdMethod(Class<?> clazz) {
        Method idMethod = null;
        // Get all public declared methods on the class. According to spec, @Id should only be
        // applied to fields and property get methods
        Method[] methods = clazz.getMethods();
        Id idAnnotation = null;
        for (Method method : methods) {
            idAnnotation = method.getAnnotation(Id.class);
            if (idAnnotation != null && !method.isBridge()) {

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Give the entity a single @Id-annotated field or getter (annotations, not XML mapping — the scanner reads reflection annotations).
  2. 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.
  3. If you must keep the composite key, wrap the lookup in your own variable type or store the individual key columns as separate variables.
  4. 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.

Example fix

// before
@EmbeddedId
private CustomerPk id; // composite -> throws
// after
@Id
@GeneratedValue
private Long id; // single-valued key
Defensive patterns

Strategy: validation

Validate before calling

for (Class<?> c = entityClass; c != null; c = c.getSuperclass()) {
  boolean hasId = Arrays.stream(c.getDeclaredFields()).anyMatch(f -> f.isAnnotationPresent(jakarta.persistence.Id.class))
    || Arrays.stream(c.getDeclaredMethods()).anyMatch(m -> m.isAnnotationPresent(jakarta.persistence.Id.class));
  if (hasId) return;
}
throw new IllegalArgumentException(entityClass + " has no single @Id field/getter");

Type guard

boolean scannableEntity(Class<?> c) { return c.isAnnotationPresent(jakarta.persistence.Entity.class) && singleIdAnnotationCount(c) == 1; }

Try / catch

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; }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/41da40a269b394cc. Report an issue: GitHub.