flowable/flowable-engine · error · FlowableObjectNotFoundException
Task ' ' doesn't have a variable ' ' in scope
Error message
Task '${taskId}' doesn't have a variable '${variableName}' in scope ${scope} What it means
This FlowableObjectNotFoundException is thrown by the CMMN REST API when a DELETE request for a task variable cannot find the named variable on the task in the requested scope (LOCAL by default, or GLOBAL/ANY). The API validates that the variable exists before deleting it, so deleting a non-existent variable fails rather than silently succeeding.
Solutions
- Set the correct scope query parameter (e.g. ?scope=global) if the variable lives in the global/case scope
- Verify the variable name via GET /cmmn-runtime/tasks/{taskId}/variables before deleting
- Check the task is still active; completed/terminated tasks may have purged variables
- Handle 404 in the client as an idempotent success if the goal is just to remove the variable
Example fix
// before
delete /cmmn-runtime/tasks/{taskId}/variables/orderId
// after
delete /cmmn-runtime/tasks/{taskId}/variables/orderId?scope=global Defensive patterns
Strategy: try-catch
Validate before calling
const vars = await fetch(`/cmmn-runtime/tasks/${taskId}/variables`); const exists = (await vars.json()).some(v => v.name === variableName); Type guard
function hasVariable(vars, name, scope) { return Array.isArray(vars) && vars.some(v => v.name === name && (scope === undefined || v.scope === undefined || v.scope === scope)); } Try / catch
try { await deleteVariable(taskId, variableName, scope); } catch (e) { if (e.status === 404 && /doesn't have a variable/.test(e.message)) { /* treat as already deleted */ } else { throw e; } } Prevention
- List a task's variables before deleting to confirm name and scope
- Always pass the explicit scope when the variable is global
- Treat 404 on delete as idempotent success in retry logic
When it happens
Trigger: DELETE /cmmn-runtime/tasks/{taskId}/variables/{variableName} (optionally with ?scope=global|local) where the task has no variable with that name in the requested scope. Note default scope is LOCAL, so a global-only variable will also trigger this if scope is not specified.
Common situations: Client caches stale variable lists after the variable was already deleted; variable exists only in GLOBAL scope but request omits scope=global; typo in variable name; task already completed and its local variables were removed.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Case instance ' ' doesn't have a variable with name: ' '.
- Could not find a case instance
- Could not find a plan item instance
- Execution ' ' does not have a variable ' ' in scope
- Historic process instance '" + processInstanceId + "'…
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/392601338875c5cb.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/task/TaskVariableResource.java:153
@ApiResponse(code = 204, message = "Indicates the task variable was found and has been deleted. Response-body is intentionally empty."),
@ApiResponse(code = 404, message = "Indicates the requested task was not found or the task does not have a variable with the given name. Status message contains additional information about the error.")
})
@DeleteMapping(value = "/cmmn-runtime/tasks/{taskId}/variables/{variableName}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteVariable(@ApiParam(name = "taskId") @PathVariable("taskId") String taskId,
@ApiParam(name = "variableName") @PathVariable("variableName") String variableName,
@ApiParam(hidden = true) @RequestParam(value = "scope", required = false) String scopeString) {
Task task = getTaskFromRequestWithoutAccessCheck(taskId);
// Determine scope
RestVariableScope scope = RestVariableScope.LOCAL;
if (scopeString != null) {
scope = RestVariable.getScopeFromString(scopeString);
}
if (!hasVariableOnScope(task, variableName, scope)) {
throw new FlowableObjectNotFoundException("Task '" + task.getId() + "' doesn't have a variable '" + variableName + "' in scope " + scope.name().toLowerCase(), VariableInstanceEntity.class);
}
if (restApiInterceptor != null) {
restApiInterceptor.deleteTaskVariables(task, Collections.singleton(variableName), scope);
}
if (scope == RestVariableScope.LOCAL) {
taskService.removeVariableLocal(task.getId(), variableName);
} else {
// Safe to use scope id, as the hasVariableOnScope would have
// stopped a global-var update on standalone task
runtimeService.removeVariable(task.getScopeId(), variableName);
}
}
}
View on GitHub (pinned to d6d39ce1c6)