flowable/flowable-engine · error · FlowableException

no update statement for ${updatedObject.getClass()} in the i

Error message

no update statement for ${updatedObject.getClass()} in the ibatis mapping files

What it means

Thrown by DbSqlSession.flushUpdateEntity when the update statement resolved for the entity's class is null after mapping. The persistence framework could not find an ibatis update statement for the entity about to be updated during command flush.

Source

Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/db/DbSqlSession.java:615

        
        if (!bulkUpdateOperations.isEmpty()) {
            bulkUpdateOperations.forEach(this::flushBulkUpdate);
        }

        if (!updatedObjects.isEmpty()) {
            updatedObjects.forEach(this::flushUpdateEntity);
        }

        updatedObjects.clear();
        bulkUpdateOperations.clear();
    }

    protected void flushUpdateEntity(Entity updatedObject) {
        String updateStatement = dbSqlSessionFactory.getUpdateStatement(updatedObject);
        updateStatement = dbSqlSessionFactory.mapStatement(updateStatement);

        if (updateStatement == null) {
            throw new FlowableException("no update statement for " + updatedObject.getClass() + " in the ibatis mapping files");
        }

        LOGGER.debug("updating: {}", updatedObject);

        int updatedRecords = sqlSession.update(updateStatement, updatedObject);
        if (updatedRecords == 0) {
            throw new FlowableOptimisticLockingException(updatedObject + " was updated by another transaction concurrently");
        }

        // See https://activiti.atlassian.net/browse/ACT-1290
        if (updatedObject instanceof HasRevision) {
            ((HasRevision) updatedObject).setRevision(((HasRevision) updatedObject).getRevisionNext());
        }
    }

    protected void flushBulkUpdate(BulkUpdateOperation bulkUpdateOperation) {
        // Bulk update
        bulkUpdateOperation.execute(sqlSession);

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Add the update statement to the entity's ibatis mapping XML (matching the name DbSqlSessionFactory.getUpdateStatement expects).
  2. Register the update statement name in DbSqlSessionFactory for the entity class.
  3. Confirm the mapping file is included in the MyBatis configuration/mapper locations.
  4. Check the entity class identity is the one the mappings were generated for (no duplicate/custom subclass).

Example fix

// before
<update id="updateMyEntity">...</update> // missing -> statement resolves to null
// after
<update id="updateMyEntity" parameterType="...">UPDATE MY_ENTITY SET ... WHERE ID_ = #{id}</update>
Defensive patterns

Strategy: validation

Validate before calling

String stmt = dbSqlSessionFactory.getBulkInsertStatement(MyEntityImpl.class);
if (stmt == null || dbSqlSessionFactory.mapStatement(stmt) == null) {
  throw new IllegalStateException("Register bulk insert statement for " + MyEntityImpl.class);
}

Try / catch

try { flushBulkInsert(entities, MyEntityImpl.class); }
catch (FlowableException e) { if (e.getMessage().startsWith("no insert statement")) { /* fix mapping / register statement */ } throw e; }

Prevention

When it happens

Trigger: Flushing a dirty entity whose class has no update statement registered in DbSqlSessionFactory (getUpdateStatement returns null), typically a custom entity whose MyBatis mapper lacks the update statement or whose mapping file was not loaded.

Common situations: Custom Entity implementations without a full mapper XML; stale/partial mapping configuration after an upgrade; entity class renamed so statement lookup keys no longer match.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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