flowable/flowable-engine · error · FlowableObjectNotFoundException

task " + taskId + " doesn't exist

Error message

task " + taskId + " doesn't exist

What it means

HasTaskVariableCmd.execute() looks up the task by id via the task service; when no TaskEntity exists for the given taskId it throws FlowableObjectNotFoundException ('task <id> doesn't exist'). This means the id is well-formed but references a task that is not in the database.

Solutions

  1. Verify the task exists first with taskService.createTaskQuery().taskId(id).count() > 0, or use hasVariable on a re-fetched TaskInfo.
  2. Re-check where the taskId is sourced from; refresh it from a fresh task query if it is stale.
  3. Confirm the engine points at the correct database and tenant for this task id.
  4. Catch FlowableObjectNotFoundException and return false / re-query instead of failing the request.

Example fix

// before
boolean has = taskService.hasVariable(taskId, "approved");
// after
if (taskService.createTaskQuery().taskId(taskId).count() == 0) {
    throw new IllegalStateException("Task no longer exists: " + taskId);
}
boolean has = taskService.hasVariable(taskId, "approved");
Defensive patterns

Strategy: try-catch

Validate before calling

boolean taskExists = taskService.createTaskQuery().taskId(taskId).count() > 0;
if (!taskExists) {
    throw new IllegalStateException("Task not found: " + taskId);
}

Type guard

boolean taskExists(String taskId) {
    return taskId != null && taskService.createTaskQuery().taskId(taskId).count() > 0;
}

Try / catch

try {
    return taskService.hasVariable(taskId, variableName);
} catch (FlowableObjectNotFoundException e) {
    log.warn("Task {} no longer exists; treating as no-variable", taskId);
    return false;
}

Prevention

When it happens

Trigger: Calling taskService.hasVariable/hasVariableLocal with a taskId that was deleted, belongs to another database/schema, or was never created (e.g. the task was completed and removed earlier).

Common situations: Stale task ids held in UI state or cached forms after task completion; environment mismatch (test DB vs prod DB); multi-tenant setups where the id comes from a different tenant's data; history cleanup removing tasks before dependent logic runs.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/cmd/HasTaskVariableCmd.java:56

        this.taskId = taskId;
        this.variableName = variableName;
        this.isLocal = isLocal;
    }

    @Override
    public Boolean execute(CommandContext commandContext) {
        if (taskId == null) {
            throw new FlowableIllegalArgumentException("taskId is null");
        }
        if (variableName == null) {
            throw new FlowableIllegalArgumentException("variableName is null");
        }

        ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
        TaskEntity task = processEngineConfiguration.getTaskServiceConfiguration().getTaskService().getTask(taskId);

        if (task == null) {
            throw new FlowableObjectNotFoundException("task " + taskId + " doesn't exist", Task.class);
        }
        boolean hasVariable = false;

        if (isLocal) {
            hasVariable = task.hasVariableLocal(variableName);
        } else {
            hasVariable = task.hasVariable(variableName);
        }

        return hasVariable;
    }
}

View on GitHub (pinned to d6d39ce1c6)