flowable/flowable-engine · error · FlowableException

Cannot access id method/field for JPA Entity

Error message

Cannot access id method/field for JPA Entity

What it means

When reading a JPA entity variable's id via reflection, Field.get threw java.lang.IllegalAccessException because the @Id field is not accessible (private/protected without setAccessible succeeding, e.g. under a security manager or module restrictions). Flowable rethrows it as this FlowableException.

Source

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

        EntityMetaData metaData = getEntityMetaData(value.getClass());
        if (!metaData.isJPAEntity()) {
            throw new FlowableIllegalArgumentException("Object is not a JPA Entity: class='" + value.getClass() + "', " + value);
        }
        Object idValue = getIdValue(value, metaData);
        return getIdString(idValue);
    }

    public Object getIdValue(Object value, EntityMetaData metaData) {
        try {
            if (metaData.getIdMethod() != null) {
                return metaData.getIdMethod().invoke(value);
            } else if (metaData.getIdField() != null) {
                return metaData.getIdField().get(value);
            }
        } catch (IllegalArgumentException iae) {
            throw new FlowableException("Illegal argument exception when getting value from id method/field on JPAEntity", iae);
        } catch (IllegalAccessException iae) {
            throw new FlowableException("Cannot access id method/field for JPA Entity", iae);
        } catch (InvocationTargetException ite) {
            throw new FlowableException("Exception occurred while getting value from id field/method on JPAEntity: " + ite.getCause().getMessage(), ite.getCause());
        }

        // Fall trough when no method and field is set
        throw new FlowableException("Cannot get id from JPA Entity, no id method/field set");
    }

    public Object getJPAEntity(String className, String idString) {
        Class<?> entityClass = null;
        entityClass = ReflectUtil.loadClass(className);

        EntityMetaData metaData = getEntityMetaData(entityClass);

        // Create primary key of right type
        Object primaryKey = createId(metaData, idString);
        return findEntity(entityClass, primaryKey);
    }

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Add a public getter for the @Id field so the idMethod branch is used instead of field reflection.
  2. Ensure Flowable can setAccessible(true): open the entity package in module-info.java (opens com.myapp.entities;) or avoid SecurityManager restrictions.
  3. Annotate the id getter rather than only the field: place @Id on the public getter.
  4. Fall back to a JDK version/profile without module restrictions or add --add-opens for the entity package.

Example fix

// before
@Id
private Long id; // private field only, no getter
// after
@Id
public Long getId() { return id; } // public getter, or add 'opens com.myapp.entities;' to module-info
Defensive patterns

Strategy: validation

Validate before calling

// verify the @Id member is reflectively accessible before use
java.lang.reflect.Field f = entity.getClass().getDeclaredField("id");
f.setAccessible(true);
f.get(entity); // throws IllegalAccessException early if still denied

Try / catch

try {
    Object v = runtimeService.getVariable(executionId, "jpaVar");
} catch (org.flowable.common.engine.api.FlowableException e) {
    if (e.getMessage().contains("Cannot access id method/field")) {
        // fall back to reading the id directly from your own entity access layer
    }
}

Prevention

When it happens

Trigger: getIdValue() falls into the metaData.getIdField().get(value) branch and the field is private/package-private and setAccessible(true) was not applied or was denied; entity class in a Java module that does not open the package to Flowable.

Common situations: Entities with an @Id field but no getter, combined with JPMS strong encapsulation (Java 9+) or a SecurityManager; OSGi/classloader setups where setAccessible is rejected; newer JDKs restricting reflection on non-opened packages.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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