flowable/flowable-engine · error · ActivitiException

no delete statement for <persistentObjectClass> in the ibati

Error message

no delete statement for <persistentObjectClass> in the ibatis mapping files

What it means

Thrown by DbSqlSession's delete operation as ActivitiException when the DbSqlSessionFactory returns no 'delete' statement mapped for the persistent object's class in the iBATIS/MyBatis mapping files. Every persistable entity must have a mapped delete statement; a missing mapping means the class is not a recognized persistable entity.

Source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/db/DbSqlSession.java:233

        }

        @Override
        public boolean sameIdentity(PersistentObject other) {
            return persistentObject.getClass().equals(other.getClass())
                    && persistentObject.getId().equals(other.getId());
        }

        @Override
        public void clearCache() {
            cacheRemove(persistentObject.getClass(), persistentObject.getId());
        }

        @Override
        public void execute() {
            String deleteStatement = dbSqlSessionFactory.getDeleteStatement(persistentObject.getClass());
            deleteStatement = dbSqlSessionFactory.mapStatement(deleteStatement);
            if (deleteStatement == null) {
                throw new ActivitiException("no delete statement for " + persistentObject.getClass() + " in the ibatis mapping files");
            }

            // It only makes sense to check for optimistic locking exceptions for objects that actually have a revision
            if (persistentObject instanceof HasRevision) {
                int nrOfRowsDeleted = sqlSession.delete(deleteStatement, persistentObject);
                if (nrOfRowsDeleted == 0) {
                    throw new ActivitiOptimisticLockingException(persistentObject + " was updated by another transaction concurrently");
                }
            } else {
                sqlSession.delete(deleteStatement, persistentObject);
            }
        }

        public PersistentObject getPersistentObject() {
            return persistentObject;
        }

        @Override

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Use the proper service API for deletion (e.g. managementService.deleteJob, taskService.deleteTask) instead of generic PersistentObject deletion.
  2. If deleting a custom entity, add a delete<ShortClassName> statement to the MyBatis mapping XML and register it via dbSqlSessionFactory.getDeleteStatements()/statementMappings.
  3. Verify engine jar versions are consistent — all Flowable/Activiti modules on the same version so mappings and classes match.
  4. Ensure you pass the actual entity class, not a subclass/DTO, to the delete path.

Example fix

// before
commandContext.getDbSqlSession().delete(myCustomDto); // no mapping for DTO class
// after
MyCustomEntity entity = commandContext.getDbSqlSession()
    .selectById(MyCustomEntity.class, id); // mapped entity with deleteMyCustomEntity statement
commandContext.getDbSqlSession().delete(entity);
Defensive patterns

Strategy: validation

Validate before calling

if (!(obj instanceof KnownActivitiEntity)) {
    throw new IllegalArgumentException(
        "Class " + obj.getClass() + " has no engine delete mapping; use a mapped entity");
}

Type guard

boolean hasDeleteMapping(Object persistentObject) {
    return persistentObject instanceof Entity; // engine-mapped persistable entities
}

Try / catch

try {
    dbSqlSession.delete(persistentObject);
} catch (ActivitiException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("no delete statement for")) {
        throw new PersistenceMappingException(persistentObject.getClass(), e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling persistence APIs (e.g. managementService.executeCommand deleting a PersistentObject) for a custom or unrecognized entity class without registering a delete statement; deleting a stale/foreign entity class through the generic dbSqlSession.executeDelete; engine jar/version mismatch where entity classes exist without matching mappings.

Common situations: Custom entities added to the engine without corresponding MyBatis XML mapping and insert/delete registration in DbSqlSessionFactory; mixing engine jar versions where a class's mapping file changed names; passing the wrong object (e.g. a DTO) to a delete path.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


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