flowable/flowable-engine · error · FlowableException

Entity does not exist: ${entityClass} - ${primaryKey}

Error message

Entity does not exist: ${entityClass} - ${primaryKey}

What it means

When deserializing a JPA entity variable from storage, Flowable loads the entity via EntityManager.find(entityClass, primaryKey). If the find returns null — no row exists for that primary key — Flowable throws this FlowableException naming the entity class and key.

Source

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

    }

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

    private Object findEntity(Class<?> entityClass, Object primaryKey) {
        EntityManager em = Context.getCommandContext().getSession(EntityManagerSession.class).getEntityManager();

        Object entity = em.find(entityClass, primaryKey);
        if (entity == null) {
            throw new FlowableException("Entity does not exist: " + entityClass.getName() + " - " + primaryKey);
        }
        return entity;
    }

    public Object createId(EntityMetaData metaData, String string) {
        Class<?> type = metaData.getIdType();
        // According to JPA-spec all primitive types (and wrappers) are
        // supported, String, util.Date, sql.Date,
        // BigDecimal and BigInteger
        if (type == Long.class || type == long.class) {
            return Long.parseLong(string);
        } else if (type == String.class) {
            return string;
        } else if (type == Byte.class || type == byte.class) {
            return Byte.parseByte(string);
        } else if (type == Short.class || type == short.class) {
            return Short.parseShort(string);
        } else if (type == Integer.class || type == int.class) {

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Restore the missing row or correct the database the engine is pointed at (verify persistence unit/DataSource matches the data that created the variable).
  2. Check the id string-to-type conversion in createId(): the parsed key (e.g. Long.parseLong) must match the @Id column type and value.
  3. Delete or fix stale variables referencing removed entities; add cleanup of process instances when their referenced entities are deleted.
  4. Guard application code: catch FlowableException around variable retrieval (getVariable of a JPA type) and handle a missing entity explicitly.

Example fix

// before
Order order = (Order) taskService.getVariable(taskId, "order"); // throws if row deleted
// after
Object v = taskService.getVariable(taskId, "order");
Order order = (v instanceof Order) ? (Order) v : orderRepository.findFallback(taskId);
Defensive patterns

Strategy: try-catch

Validate before calling

// verify the referenced entity exists before relying on the variable
Object key = taskService.getVariable(taskId, "orderId");
boolean exists = key != null && entityManager.find(Order.class, key) != null;

Type guard

boolean entityExists(EntityManager em, Class<?> type, Object pk) {
    return pk != null && em.find(type, pk) != null;
}

Try / catch

try {
    Object v = runtimeService.getVariable(executionId, "jpaVar");
} catch (org.flowable.common.engine.api.FlowableException e) {
    if (e.getMessage().startsWith("Entity does not exist")) {
        // handle deleted entity: re-create, reassign variable, or complete/terminate the process
    }
}

Prevention

When it happens

Trigger: findEntity() called from getJPAEntity(className, idString): the stored variable references an entity whose row was deleted from the database, or the primary key string was converted to a value that no longer matches any row (wrong createId type, e.g. Long vs String mismatch).

Common situations: Referential integrity without FK constraints: process variables outlive the entity rows; data purged by cleanup jobs or cascading deletes while the process instance still holds a JPA variable; running against a different database/environment than the one the variable was created in; id type conversion (createId) producing a differently-typed key that finds nothing.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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