flowable/flowable-engine · error · FlowableObjectNotFoundException
task ${taskId} doesn't exist
Error message
task ${taskId} doesn't exist What it means
HasTaskVariableCmd.execute throws FlowableObjectNotFoundException when the taskId is non-null but no matching task exists in the task service. The engine fetches the task via the task service before evaluating variables; a null result means the variable question cannot be answered for a nonexistent task.
Source
Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/HasTaskVariableCmd.java:57
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");
}
CmmnEngineConfiguration cmmnEngineConfiguration = CommandContextUtil.getCmmnEngineConfiguration(commandContext);
TaskEntity task = cmmnEngineConfiguration.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)
Solutions
- Check task existence first via taskService.createTaskQuery().taskId(id).singleResult()
- For completed tasks use the history service task query/variables APIs
- Verify the id source and that you target the correct database/schema
Example fix
// before boolean has = taskService.hasVariable(taskId, "approved"); // after Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); boolean has = task != null && taskService.hasVariable(taskId, "approved");
Defensive patterns
Strategy: try-catch
Validate before calling
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
if (task == null) {
// task completed/deleted; fall back to history
} Type guard
boolean taskExists(TaskService ts, String id) {
return id != null && ts.createTaskQuery().taskId(id).singleResult() != null;
} Try / catch
try {
return taskService.hasVariable(taskId, variableName);
} catch (FlowableObjectNotFoundException e) {
log.warn("Task {} not found; checking history", taskId);
return historyService.createHistoricVariableInstanceQuery()
.taskId(taskId).variableName(variableName).count() > 0;
} Prevention
- Use history APIs for completed tasks rather than runtime task service
- Re-resolve task ids instead of caching them long-term
- Ensure all nodes point to the same database/schema
When it happens
Trigger: Calling hasVariable with a task id of a completed/deleted task, a typo'd id, or an id belonging to another engine/database.
Common situations: Working with historic tasks (query runtime task service instead of history), stale ids cached in the application, hard-coded test ids, or cross-environment database confusion.
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
- Cannot find task with id ${taskId}
- Cannot resume task with id '
- Cannot find case instance for id ${caseInstanceId}
- Cannot find plan item instance for id ${planItemInstanceId}
- taskId is null
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/6a894598d9c8f8d8.
Report an issue: GitHub.