flowable/flowable-engine · warning · FlowableException
Case instance '
Error message
Case instance '
What it means
Flowable CMMN throws this when calling CaseInstanceClaimCmd.execute for a case instance that already has an ASSIGNEE identity link, i.e. it has already been claimed by a user. Claiming is a one-time operation; re-claiming without unclaiming first is rejected to protect the existing assignee.
Solutions
- Check whether the case instance is already claimed before calling claim, e.g. via identityLinkService.findIdentityLinksByScopeIdAndType(caseInstanceId, ScopeTypes.CMMN) and looking for an ASSIGNEE link
- Catch FlowableException and treat the 'is already claimed' message as an expected business condition, informing the user who holds the claim
- If reassignment is intended, unclaim the case instance (remove assignee identity link) before claiming with the new user
- Fix duplicate claim submission in the UI by disabling the claim action once a claim succeeds
Example fix
// before
caseInstanceService.claim(caseInstanceId, userId); // throws if already claimed
// after
List<IdentityLink> links = identityLinkService.findIdentityLinksByScopeIdAndType(caseInstanceId, ScopeTypes.CMMN);
boolean claimed = links.stream().anyMatch(l -> IdentityLinkType.ASSIGNEE.equals(l.getType()));
if (!claimed) {
caseInstanceService.claim(caseInstanceId, userId);
} Defensive patterns
Strategy: try-catch
Validate before calling
boolean alreadyClaimed = cmmnEngineConfig.getIdentityLinkServiceConfiguration().getIdentityLinkService()
.findIdentityLinksByScopeIdAndType(caseInstanceId, ScopeTypes.CMMN).stream()
.anyMatch(l -> IdentityLinkType.ASSIGNEE.equals(l.getType()));
if (alreadyClaimed) { /* skip claim or show holder */ } Try / catch
try {
caseInstanceService.claim(caseInstanceId, userId);
} catch (FlowableException e) {
if (e.getMessage() != null && e.getMessage().contains("is already claimed")) {
// surface friendly message to user
} else {
throw e;
}
} Prevention
- Query identity links for an existing ASSIGNEE before claiming
- Disable claim buttons once a claim succeeds and refresh case state
- Handle retry/idempotency in workflows that re-submit claims
When it happens
Trigger: Calling CmmnTaskService/cmmnEngine CaseInstanceService.claim(caseInstanceId, userId) on a case instance where findIdentityLinksByScopeIdAndType returns an identity link of type ASSIGNEE.
Common situations: Two users clicking a 'claim' button concurrently; a retry of a claim request after it already succeeded; UI not refreshing claim state after another user claimed; batch job reprocessing the same case instance.
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
- Local variable ' ' is already present on plan item instance…
- No case instance found for id = '
- Task '
- The case instance id is mandatory, but '
- A dynamically created plan item can only be injected into a…
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/2c1b04e51111f82d.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/CaseInstanceClaimCmd.java:63
this.caseInstanceId = caseInstanceId;
this.userId = userId;
}
@Override
public Void execute(CommandContext commandContext) {
CaseInstanceEntityManager caseInstanceEntityManager = CommandContextUtil.getCaseInstanceEntityManager(commandContext);
CaseInstanceEntity caseInstanceEntity = caseInstanceEntityManager.findById(caseInstanceId);
if (caseInstanceEntity == null) {
throw new FlowableObjectNotFoundException("No case instance found for id = '" + caseInstanceId + "'.", CaseInstance.class);
}
CmmnEngineConfiguration cmmnEngineConfiguration = CommandContextUtil.getCmmnEngineConfiguration(commandContext);
if (userId != null) {
List<IdentityLinkEntity> identityLinks = cmmnEngineConfiguration.getIdentityLinkServiceConfiguration()
.getIdentityLinkService().findIdentityLinksByScopeIdAndType(caseInstanceId, ScopeTypes.CMMN);
for (IdentityLinkEntity identityLink : identityLinks) {
if (IdentityLinkType.ASSIGNEE.equals(identityLink.getType())) {
throw new FlowableException("Case instance '" + caseInstanceId + "' is already claimed.");
}
}
IdentityLinkUtil.createCaseInstanceIdentityLink(caseInstanceEntity, userId, null, IdentityLinkType.ASSIGNEE, cmmnEngineConfiguration);
caseInstanceEntityManager.updateCaseInstanceClaimTime(caseInstanceEntity, cmmnEngineConfiguration.getClock().getCurrentTime(), userId);
if (cmmnEngineConfiguration.getCaseInstanceStateInterceptor() != null) {
cmmnEngineConfiguration.getCaseInstanceStateInterceptor().handleClaim(caseInstanceEntity, userId);
}
} else {
IdentityLinkUtil.deleteCaseInstanceIdentityLinks(caseInstanceEntity, null, null, IdentityLinkType.ASSIGNEE, cmmnEngineConfiguration);
caseInstanceEntityManager.updateCaseInstanceClaimTime(caseInstanceEntity, null, null);
if (cmmnEngineConfiguration.getCaseInstanceStateInterceptor() != null) {
cmmnEngineConfiguration.getCaseInstanceStateInterceptor().handleUnclaim(caseInstanceEntity, userId);View on GitHub (pinned to d6d39ce1c6)