flowable/flowable-engine · error · ActivitiIllegalArgumentException

Object is not a JPA Entity: class='${value.getClass()}', ${v

Error message

Object is not a JPA Entity: class='${value.getClass()}', ${value}

What it means

getJPAClassString validates that the value's class is annotated as a JPA entity (via EntityMetaData.isJPAEntity). If the object lacks @Entity (or valid JPA metadata), it cannot be stored as a JPA entity variable, so this error is thrown.

Source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/variable/JPAEntityMappings.java:76

            // Class not present in meta-data map, create metaData for it and add
            metaData = scanClass(clazz);
            classMetaDatamap.put(clazz.getName(), metaData);
        }
        return metaData;
    }

    private EntityMetaData scanClass(Class<?> clazz) {
        return enitityScanner.scanClass(clazz);
    }

    public String getJPAClassString(Object value) {
        if (value == null) {
            throw new ActivitiIllegalArgumentException("null value cannot be saved");
        }

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

        // Extract the class from the Entity instance
        return metaData.getEntityClass().getName();
    }

    public String getJPAIdString(Object value) {
        EntityMetaData metaData = getEntityMetaData(value.getClass());
        if (!metaData.isJPAEntity()) {
            throw new ActivitiIllegalArgumentException("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) {

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Annotate the class with @Entity and ensure it has a valid @Id
  2. Verify you are storing the actual entity, not a DTO or wrapper
  3. Check the JPA/persistence configuration so entity scanning sees the class
  4. If a plain object is intended, do not use the JPA entity variable mapping

Example fix

// before
public class Order { private Long id; ... }
runtimeService.setVariable(executionId, "order", new Order());
// after
@Entity
public class Order { @Id private Long id; ... }
Defensive patterns

Strategy: type-guard

Validate before calling

if (!value.getClass().isAnnotationPresent(Entity.class)) {
    throw new IllegalArgumentException(value.getClass() + " is not a JPA entity");
}

Type guard

boolean isJpaEntity(Object v) {
    return v != null && v.getClass().isAnnotationPresent(javax.persistence.Entity.class);
}

Try / catch

try {
    runtimeService.setVariable(id, "order", value);
} catch (ActivitiIllegalArgumentException e) {
    if (e.getMessage().startsWith("Object is not a JPA Entity")) {
        // store as serializable instead
        runtimeService.setVariable(id, "order", (Serializable) value);
    } else { throw e; }
}

Prevention

When it happens

Trigger: Passing a plain POJO, DTO, collection, String, or an un-annotated class to a variable API that resolves to the JPA entity variable type, or an entity whose metadata scanning failed (missing @Entity annotation).

Common situations: Putting a DTO into a process variable while a JPA entity type was expected; forgetting @Entity on the class; entity class from another persistence unit not scanned; proxy classes (Hibernate) wrapping the entity in odd configurations.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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