flowable/flowable-engine · error · FlowableTaskAlreadyClaimedException

Task '' is already claimed by someone else.

Error message

Task '' is already claimed by someone else.

What it means

ClaimTaskCmd claims a task for a user. If the task already has an assignee different from the claiming user, Flowable throws FlowableTaskAlreadyClaimedException; claiming by the same assignee is silently ignored.

Source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/cmd/ClaimTaskCmd.java:60

    protected Void execute(CommandContext commandContext, TaskEntity task) {
        if (Flowable5Util.isFlowable5ProcessDefinitionId(commandContext, task.getProcessDefinitionId())) {
            Flowable5CompatibilityHandler compatibilityHandler = Flowable5Util.getFlowable5CompatibilityHandler();
            compatibilityHandler.claimTask(taskId, userId);
            return null;
        }

        ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
        if (userId != null) {
            Clock clock = processEngineConfiguration.getClock();
            task.setClaimTime(clock.getCurrentTime());
            task.setClaimedBy(userId);
            task.setState(Task.CLAIMED);

            if (task.getAssignee() != null) {
                if (!task.getAssignee().equals(userId)) {
                    // When the task is already claimed by another user, throw
                    // exception. Otherwise, ignore this, post-conditions of method already met.
                    throw new FlowableTaskAlreadyClaimedException(task.getId(), task.getAssignee());
                }
                CommandContextUtil.getActivityInstanceEntityManager(commandContext).recordTaskInfoChange(task, clock.getCurrentTime());
                
            } else {
                TaskHelper.changeTaskAssignee(task, userId);
                
                if (processEngineConfiguration.getUserTaskStateInterceptor() != null) {
                    processEngineConfiguration.getUserTaskStateInterceptor().handleClaim(task, userId);
                }
            }
            
            CommandContextUtil.getHistoryManager().createUserIdentityLinkComment(task, userId, IdentityLinkType.ASSIGNEE, true);
            
        } else {
            if (task.getAssignee() != null) {
                // Task claim time should be null
                task.setClaimTime(null);
                task.setClaimedBy(null);

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Catch FlowableTaskAlreadyClaimedException and refresh the task state / notify the user.
  2. Use taskService.createTaskQuery().taskId(id).taskAssignee(userId) beforehand to check current assignee.
  3. Call taskService.unclaim(taskId) first if reassignment is intended (with appropriate authorization).

Example fix

// before
taskService.claim(taskId, userId);
// after
try {
    taskService.claim(taskId, userId);
} catch (FlowableTaskAlreadyClaimedException e) {
    // task already assigned to e.getCurrentAssignee(); refresh UI
}
Defensive patterns

Strategy: try-catch

Validate before calling

Task t = taskService.createTaskQuery().taskId(taskId).singleResult();
boolean claimable = t != null && t.getAssignee() == null;

Try / catch

try {
    taskService.claim(taskId, userId);
} catch (FlowableTaskAlreadyClaimedException e) {
    // refresh UI, show current assignee e.getCurrentAssignee()
}

Prevention

When it happens

Trigger: taskService.claim(taskId, userId) where the task's current assignee is another user; two users claiming concurrently.

Common situations: Collaborative task lists where multiple users click 'claim' at once; retrying a claim after another user already took it; stale UI showing the task as unclaimed.

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/cdbb5ce48db7b4ea. Report an issue: GitHub.