Activiti/Activiti · error · ActivitiException

Entity does not exist

Error message

Entity does not exist: ${entityClass.getName()} - ${primaryKey}

What it means

findEntity resolves a stored JPA variable back into a live entity by calling EntityManager.find(entityClass, primaryKey). If the persistence provider returns null — no row with that primary key exists — Activiti throws ActivitiException 'Entity does not exist: <class> - <pk>'. The variable references an entity that has been deleted or never existed in the database.

Solutions

  1. Recreate/restore the missing row with the stored primary key.
  2. Fix referential hygiene: prevent deletion of entities referenced by running process variables (FK constraints or soft-delete).
  3. Verify the persistence unit/datasource points at the same database the variable was created against.

Example fix

// before
customerRepository.delete(customer); // row referenced by running process
// after
// soft delete or verify no active process variables reference the entity first
if (!hasActiveProcessReferences(customer.getId())) {
    customerRepository.delete(customer);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before relying on the variable, check the row still exists
Object pk = /* stored primary key */;
Object entity = entityManager.find(Order.class, pk);
if (entity == null) {
    logger.warn("Order " + pk + " no longer exists; handle or fail the process step");
}

Try / catch

try {
    Order order = (Order) runtimeService.getVariable(executionId, "order");
} catch (ActivitiException e) {
    if (e.getMessage().startsWith("Entity does not exist")) {
        logger.warn("Referenced entity deleted; compensating...");
        // take alternate path or restore the row
    } else { throw e; }
}

Prevention

When it happens

Trigger: Deserializing a JPA process variable whose stored primary key no longer matches any DB row, e.g. during process execution after the referenced row was deleted, or with a variable saved against a different database/environment than the one currently configured.

Common situations: Entity rows purged by cleanup jobs or cascading deletes while processes referencing them still run; pointing the engine at a different schema/test DB that lacks the row; restoring process data without restoring entity data.

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 Activiti/Activiti@56435b1a97 (2026-09-09). Data as JSON: /api/errors/b1ddf95d851dbe02. Report an issue: GitHub.

Appendix: source

Thrown at activiti-core/activiti-engine/src/main/java/org/activiti/engine/impl/variable/JPAEntityMappings.java:138

    }

    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 ActivitiException("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 56435b1a97)