flowable/flowable-engine · error · FlowableOptimisticLockingException
Could not lock case instance
Error message
Could not lock case instance
What it means
Thrown by MybatisCaseInstanceDataManagerImpl.updateLockTime when the directUpdate on updateCaseInstanceLockTime affects 0 rows. This is an optimistic-locking style failure: the engine tried to acquire a lock on a case instance but the row no longer matches the expected state (deleted or concurrently locked).
Source
Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/persistence/entity/data/impl/MybatisCaseInstanceDataManagerImpl.java:198
}
@Override
public long countByCriteria(CaseInstanceQueryImpl query) {
setSafeInValueLists(query);
return (Long) getDbSqlSession().selectOne("selectCaseInstanceCountByQueryCriteria", query);
}
@Override
public void updateLockTime(String caseInstanceId, Date lockDate, String lockOwner, Date expirationTime) {
HashMap<String, Object> params = new HashMap<>();
params.put("id", caseInstanceId);
params.put("lockTime", lockDate);
params.put("expirationTime", expirationTime);
params.put("lockOwner", lockOwner);
int result = getDbSqlSession().directUpdate("updateCaseInstanceLockTime", params);
if (result == 0) {
throw new FlowableOptimisticLockingException("Could not lock case instance");
}
}
@Override
public void clearLockTime(String caseInstanceId) {
HashMap<String, Object> params = new HashMap<>();
params.put("id", caseInstanceId);
getDbSqlSession().directUpdate("clearCaseInstanceLockTime", params);
}
@Override
public void clearAllLockTimes(String lockOwner) {
HashMap<String, Object> params = new HashMap<>();
params.put("lockOwner", lockOwner);
getDbSqlSession().directUpdate("clearAllCaseInstanceLockTimes", params);
}
protected void setSafeInValueLists(CaseInstanceQueryImpl caseInstanceQuery) {View on GitHub (pinned to d6d39ce1c6)
Solutions
- Retry the operation after re-fetching the case instance to confirm it still exists
- Catch FlowableOptimisticLockingException and treat it as 'another node holds the lock', rescheduling the work
- Verify the case instance was not concurrently deleted before attempting to lock
Example fix
// before
entityManager.updateLockTime(caseInstanceId, lockOwner, lockDate, expirationTime); // throws if row gone
// after
try {
entityManager.updateLockTime(caseInstanceId, lockOwner, lockDate, expirationTime);
} catch (FlowableOptimisticLockingException e) {
// another node locked or the instance was removed; reschedule or skip
} Defensive patterns
Strategy: retry
Try / catch
try {
entityManager.updateLockTime(caseInstanceId, lockOwner, lockDate, expirationTime);
} catch (FlowableOptimisticLockingException e) {
// re-fetch instance; retry with backoff or skip if deleted
} Prevention
- Limit concurrent mutations of the same case instance
- Use short transactions around lock acquisition
- Detect and surface concurrent case instance deletion instead of blindly locking
When it happens
Trigger: Calling updateLockTime(caseInstanceId, ...) when the case instance row has already been deleted or its LOCK_TIME_/LOCK_OWNER_/EXPIRATION_TIME_ state changed concurrently so the conditional update matched nothing.
Common situations: Long-running or heavily concurrent case operations where two threads race for the lock; stale entity references after a case instance was terminated and removed; distributed engine nodes with unsynchronized caches.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Task '
- Can only enable a plan item instance which is in state ENABL
- ${updatedObject} was updated by another transaction concurre
- ${entity} was updated by another transaction concurrently
- Could not lock process instance
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/69fbd84b86ac5d18.
Report an issue: GitHub.