flowable/flowable-engine · error · FlowableIllegalArgumentException

Can only complete a case instance which is marked as complet

Error message

Can only complete a case instance which is marked as completeable. Check if there are active plan item instances.

What it means

CompleteCaseInstanceCmd only completes a case instance whose state is marked completable — meaning the case plan has no active plan item instances blocking completion. If caseInstanceEntity.isCompletable() is false, Flowable throws FlowableIllegalArgumentException instructing you to check for active plan item instances.

Source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/CompleteCaseInstanceCmd.java:32

import org.flowable.cmmn.engine.impl.persistence.entity.CaseInstanceEntity;
import org.flowable.cmmn.engine.impl.util.CommandContextUtil;
import org.flowable.common.engine.api.FlowableIllegalArgumentException;
import org.flowable.common.engine.impl.interceptor.CommandContext;

/**
 * @author Joram Barrez
 */
public class CompleteCaseInstanceCmd extends AbstractNeedsCaseInstanceCmd {

    public CompleteCaseInstanceCmd(String caseInstanceId) {
        super(caseInstanceId);
    }
    
    @Override
    protected void internalExecute(CommandContext commandContext, CaseInstanceEntity caseInstanceEntity) {
        if (!caseInstanceEntity.isCompletable()) {
            throw new FlowableIllegalArgumentException("Can only complete a case instance which is marked as completeable. Check if there are active plan item instances.");
        }
        CommandContextUtil.getAgenda(commandContext).planCompleteCaseInstanceOperation(caseInstanceEntity);
    }

}

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Terminate/complete all active plan item instances (tasks, stages) first, then call completeCaseInstance.
  2. If the case should be abandoned regardless, use cmmnRuntimeService.terminateCaseInstance(caseInstanceId) instead.
  3. Query plan items first to confirm none active: cmmnRuntimeService.createPlanItemInstanceQuery().caseInstanceId(id).stateActive().count() == 0.
  4. If you control the model, ensure the plan completes automatically (e.g. required/completion rules) so the instance reaches completable state.

Example fix

// before
cmmnRuntimeService.completeCaseInstance(caseInstanceId); // may throw if active plan items exist

// after
long active = cmmnRuntimeService.createPlanItemInstanceQuery()
    .caseInstanceId(caseInstanceId).stateActive().count();
if (active > 0) {
    cmmnRuntimeService.terminateCaseInstance(caseInstanceId);
} else {
    cmmnRuntimeService.completeCaseInstance(caseInstanceId);
}
Defensive patterns

Strategy: try-catch

Validate before calling

long active = cmmnRuntimeService.createPlanItemInstanceQuery().caseInstanceId(id).stateActive().count();
boolean canComplete = active == 0;

Try / catch

try { cmmnRuntimeService.completeCaseInstance(id); } catch (FlowableIllegalArgumentException e) { /* case not completable; terminate instead */ }

Prevention

When it happens

Trigger: Calling cmmnRuntimeService.completeCaseInstance(caseInstanceId) while the case still has active (not yet completed/terminated) plan item instances, so the case instance is not in the completable state.

Common situations: Attempting programmatic termination of a running case without first ending its active human tasks/stages; assuming completeCaseInstance works like process instance delete; racing with plan items still activating.

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


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