flowable/flowable-engine · error · FlowableObjectNotFoundException

Execution ' ' does not have a variable ' ' in scope

Error message

Execution '${executionId}' does not have a variable '${variableName}' in scope ${scope}

What it means

DELETE on a process-instance variable checks hasVariableOnScope for the execution and the requested scope (local by default, or 'global'/'shared'). If the execution does not have that variable in that scope, Flowable throws FlowableObjectNotFoundException naming the execution, variable, and scope.

Solutions

  1. Fetch GET /runtime/process-instances/{id}/variables first and confirm the variable name and its scope.
  2. Add the correct scope query parameter, e.g. ?scope=global, when the variable is on the process instance rather than local.
  3. Check for typos or case differences in variableName.
  4. Make deletion idempotent in client code: treat 404 as already-deleted and skip.

Example fix

// before
curl -X DELETE .../process-instances/123/variables/orderId  // variable is global

// after
curl -X DELETE .../process-instances/123/variables/orderId?scope=global
Defensive patterns

Strategy: try-catch

Validate before calling

const vars = await api.get(`/process-instances/${id}/variables`);
const v = vars.data.find(v => v.name === variableName);
if (!v) throw new Error(`Variable ${variableName} not present; nothing to delete`);
const scopeParam = v.scope === 'global' ? '?scope=global' : '';

Type guard

function hasVariable(vars, name) { return Array.isArray(vars) && vars.some(v => v.name === name); }

Try / catch

try {
  await api.delete(`/process-instances/${id}/variables/${name}${scopeParam}`);
} catch (e) {
  if (e.response?.status === 404) { /* already gone; treat as idempotent success */ }
  else throw e;
}

Prevention

When it happens

Trigger: DELETE /runtime/process-instances/{id}/variables/{variableName} (optionally ?scope=local|global) where the variable was never set, was already deleted, exists only in the other scope (e.g. variable is global but default scope=local is queried), or the execution id is wrong.

Common situations: Deleting a variable inherited from the process instance while omitting scope=global, double-delete retries, typos in variable names, variables set on a parent execution rather than the addressed one.

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

Appendix: source

Thrown at modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ProcessInstanceVariableResource.java:194

    @ApiOperation(value = "Delete a variable", tags = { "Process Instance Variables" }, nickname = "deleteProcessInstanceVariable", code = 204)
    @ApiResponses(value = {
            @ApiResponse(code = 204, message = "Indicates the variable was found and has been deleted. Response-body is intentionally empty."),
            @ApiResponse(code = 404, message = "Indicates the requested variable was not found.")
    })
    @DeleteMapping(value = "/runtime/process-instances/{processInstanceId}/variables/{variableName}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void deleteVariable(@ApiParam(name = "processInstanceId") @PathVariable("processInstanceId") String processInstanceId, @ApiParam(name = "variableName") @PathVariable("variableName") String variableName,
            @RequestParam(value = "scope", required = false) String scope) {

        Execution execution = getExecutionFromRequestWithoutAccessCheck(processInstanceId);
        // Determine scope
        RestVariableScope variableScope = RestVariableScope.LOCAL;
        if (scope != null) {
            variableScope = RestVariable.getScopeFromString(scope);
        }

        if (!hasVariableOnScope(execution, variableName, variableScope)) {
            throw new FlowableObjectNotFoundException("Execution '" + execution.getId() + "' does not have a variable '" + variableName + "' in scope " + variableScope.name().toLowerCase(),
                    VariableInstanceEntity.class);
        }

        if (restApiInterceptor != null) {
            restApiInterceptor.deleteExecutionVariables(execution, Collections.singleton(variableName), variableScope);
        }

        if (variableScope == RestVariableScope.LOCAL) {
            runtimeService.removeVariableLocal(execution.getId(), variableName);
        } else {
            // Safe to use parentId, as the hasVariableOnScope would have
            // stopped a global-var update on a root-execution
            runtimeService.removeVariable(execution.getParentId(), variableName);
        }
    }

    @Override
    protected RestVariable constructRestVariable(String variableName, Object value, RestVariableScope variableScope, String executionId, boolean includeBinary) {

View on GitHub (pinned to d6d39ce1c6)