{"record":{"id":"2191f5763a6cde7a","repo":"flowable/flowable-engine","slug":"no-delete-statement-for-entity-getclass-in-th","errorCode":null,"errorMessage":"no delete statement for ${entity.getClass()} in the ibatis mapping files","messagePattern":"no delete statement for (.+?) in the ibatis mapping files","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/db/DbSqlSession.java","lineNumber":682,"sourceCode":"        deletedObjects.clear();\n        bulkDeleteOperations.clear();\n    }\n\n    protected void flushBulkDeletes(Class<? extends Entity> entityClass, List<BulkDeleteOperation> deleteOperations) {\n        // Bulk deletes\n        if (deleteOperations != null) {\n            for (BulkDeleteOperation bulkDeleteOperation : deleteOperations) {\n                bulkDeleteOperation.execute(sqlSession, entityClass);\n            }\n        }\n    }\n\n    protected void flushDeleteEntities(Class<? extends Entity> entityClass, Collection<Entity> entitiesToDelete) {\n        for (Entity entity : entitiesToDelete) {\n            String deleteStatement = dbSqlSessionFactory.getDeleteStatement(entity.getClass());\n            deleteStatement = dbSqlSessionFactory.mapStatement(deleteStatement);\n            if (deleteStatement == null) {\n                throw new FlowableException(\"no delete statement for \" + entity.getClass() + \" in the ibatis mapping files\");\n            }\n\n            // It only makes sense to check for optimistic locking exceptions\n            // for objects that actually have a revision\n            if (entity instanceof HasRevision) {\n                int nrOfRowsDeleted = sqlSession.delete(deleteStatement, entity);\n                if (nrOfRowsDeleted == 0) {\n                    throw new FlowableOptimisticLockingException(entity + \" was updated by another transaction concurrently\");\n                }\n            } else {\n                sqlSession.delete(deleteStatement, entity);\n            }\n        }\n    }\n\n    @Override\n    public void close() {\n        sqlSession.close();","sourceCodeStart":664,"sourceCodeEnd":700,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/db/DbSqlSession.java#L664-L700","documentation":"Thrown by DbSqlSession.flushDeleteEntities when the delete statement for the entity class resolves to null after statement mapping. No ibatis delete statement is registered for the entity type being deleted.","triggerScenarios":"Deleting an entity (Entity.remove / persistence API) whose class has no delete statement name registered in DbSqlSessionFactory, or whose mapping XML lacks the delete statement.","commonSituations":"Custom entities with incomplete mapper XML (insert present, delete missing); mappings not deployed after an upgrade; class name changes breaking statement lookup.","solutions":["Add the delete statement to the entity's ibatis mapping XML.","Register the delete statement name in DbSqlSessionFactory (setDeleteStatement) for the entity class.","Verify the mapper XML is on the classpath and included in the MyBatis configuration.","Compare against a built-in entity's mapping to ensure statement id and parameter conventions match."],"exampleFix":"// before\n// no delete in mapper -> null statement\n// after\n<delete id=\"deleteMyEntity\" parameterType=\"...\">DELETE FROM MY_ENTITY WHERE ID_ = #{id} AND REV_ = #{revision}</delete>","handlingStrategy":"retry","validationCode":"long cnt = taskService.createTaskQuery().taskId(id).count();\nif (cnt == 0) throw new IllegalStateException(\"Task gone: \" + id);\n// reload entity right before modification so revision is fresh\nTask fresh = taskService.createTaskQuery().taskId(id).singleResult();\nfresh.setName(name);","typeGuard":null,"tryCatchPattern":"try { /* modify + save */ }\ncatch (FlowableOptimisticLockingException e) {\n  // reload entity with fresh revision and retry the whole command (bounded retries)\n}","preventionTips":["Reload entities from the engine immediately before modifying; don't cache across transactions.","Use exclusive jobs for async work touching shared process data.","Keep user-facing transactions short.","Design handlers idempotently so safe retries are possible."],"tags":["database","ibatis","persistence","missing-statement"],"backgroundTag":"internal-invariant-violation","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}