flowable/flowable-engine · error · FlowableObjectNotFoundException

Task '${taskId}' does not have a variable '${variableName}'

Error message

Task '${taskId}' does not have a variable '${variableName}' in scope ${scope}

What it means

Deleting a task variable (DELETE /runtime/tasks/{taskId}/variables/{variableName}) first checks that the variable exists in the requested scope (local by default, or global when ?scope=global). If the task does not have that variable in that scope, FlowableObjectNotFoundException is thrown (with VariableInstanceEntity as the missing type), mapping to HTTP 404. It prevents deleting non-existent variables and distinguishes local vs. process-level (global) scopes.

Source

Thrown at modules/flowable-rest/src/main/java/org/flowable/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 = "/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() + "' does not 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 executionId, as the hasVariableOnScope would have
            // stopped a global-var update on standalone task
            runtimeService.removeVariable(task.getExecutionId(), variableName);
        }
    }
}

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Add ?scope=global when the variable was set at the process/execution level rather than on the task.
  2. GET the task's variables first to confirm the exact name and scope before deleting.
  3. Fix the task id / variable name (names are case-sensitive).
  4. Treat 404 as idempotent success if deletion may have already happened.

Example fix

// before: variable is global (set on process), default local scope fails
curl -X DELETE .../runtime/tasks/123/variables/orderStatus

// after
curl -X DELETE .../runtime/tasks/123/variables/orderStatus?scope=global
Defensive patterns

Strategy: validation

Validate before calling

const vars = await fetch(`/runtime/tasks/${taskId}/variables?scope=${scope}`).then(r => r.json());
if (!vars.some(v => v.name === variableName)) {
  return; // nothing to delete; skip the DELETE call
}

Try / catch

try {
  const resp = await fetch(url, { method: 'DELETE' });
  if (resp.status === 404) return; // idempotent: already gone or wrong scope
  if (!resp.ok) throw new Error(await resp.text());
} catch (e) {
  if (!isNotFound(e)) throw e;
}

Prevention

When it happens

Trigger: DELETE /runtime/tasks/{taskId}/variables/{variableName}[?scope=local|global] where the variable is not present on the task in the given scope: variable was already deleted, variable exists only at process/execution (global) scope while scope=local is used, name typo, or variable belongs to a different task.

Common situations: Variables set at process start are global, but the default scope for this call is local, so deleting them from a task with default scope 404s; double-delete in retry logic; wrong task id; case-sensitive name mismatch.

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


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