flowable/flowable-engine · error · FlowableObjectNotFoundException

Plan item instance '${id}' does not have a variable '${varia

Error message

Plan item instance '${id}' does not have a variable '${variableName}' in local scope

What it means

deleteVariable checks runtimeService.hasLocalVariable(planItem.getId(), variableName); when the plan item instance has no such variable in LOCAL scope it throws FlowableObjectNotFoundException with VariableInstance.class. Only local scope is consulted here — an instance-scope (case) variable with the same name will not satisfy this check.

Source

Thrown at modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/PlanItemInstanceVariableResource.java:178

            setSimpleVariable(restVariable, planItem.getId(), false, true, RestVariable.RestVariableScope.LOCAL, CmmnRestResponseFactory.VARIABLE_PLAN_ITEM, createVariableInterceptor(planItem));
        }
    }

    @ApiOperation(value = "Delete a variable for a plan item instance", tags = { "Plan Item Instances" }, nickname = "deletePlanItemVariable", code = 204)
    @ApiResponses(value = {
            @ApiResponse(code = 204, message = "Indicates both the plan item and variable were found and variable has been deleted."),
            @ApiResponse(code = 404, message = "Indicates the requested plan item was not found or the plan item does not have a variable with the given name in the requested scope. Status description contains additional information about the error.")
    })
    @ResponseStatus(HttpStatus.NO_CONTENT)
    @DeleteMapping(value = "/cmmn-runtime/plan-item-instances/{planItemInstanceId}/variables/{variableName}")
    public void deleteVariable(@ApiParam(name = "planItemInstanceId") @PathVariable("planItemInstanceId") String planItemInstanceId,
            @ApiParam(name = "variableName") @PathVariable("variableName") String variableName,
            @RequestParam(value = "scope", required = false) String scope) {

        PlanItemInstance planItem = getPlanItemInstanceFromRequest(planItemInstanceId);

        if (!runtimeService.hasLocalVariable(planItem.getId(), variableName)) {
            throw new FlowableObjectNotFoundException(
                    "Plan item instance '" + planItem.getId() + "' does not have a variable '" + variableName + "' in local scope",
                    VariableInstance.class);
        }

        if (restApiInterceptor != null) {
            restApiInterceptor.deletePlanItemInstanceVariables(planItem, Collections.singleton(variableName));
        }
        runtimeService.removeLocalVariable(planItem.getId(), variableName);
    }
}

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Check the variable exists locally via GET .../variables?scope=local before deleting.
  2. If the variable lives in case scope, delete it via the case-instance variable endpoint instead.
  3. Handle 404 idempotently — deleting an already-deleted variable should be treated as success by the caller.
  4. Verify planItemInstanceId is from an active case instance.

Example fix

// before
delete("/plan-item-instances/" + id + "/variables/" + name); // may 404 if only case-scoped
// after
if (get("/plan-item-instances/" + id + "/variables/" + name + "?scope=local")) {
  delete("/plan-item-instances/" + id + "/variables/" + name);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check local existence
const vars = rest.get(`/cmmn-runtime/plan-item-instances/${id}/variables?scope=local`);
if (!vars.some(v => v.name === variableName)) return; // nothing local to delete

Try / catch

try { api.deletePlanItemVariable(planItemId, name); }
catch (FlowableObjectNotFoundException e) {
  if (e.getResourceClass() == VariableInstance.class) { log.info('already deleted or case-scoped'); return; }
  throw e;
}

Prevention

When it happens

Trigger: DELETE /cmmn-runtime/plan-item-instances/{planItemInstanceId}/variables/{variableName} where the variable was never set locally, was already deleted, or exists only in case (global) scope.

Common situations: Assuming variables set on the case are visible as plan-item-local variables; double DELETE from concurrent workers; variable removed by a completed plan item; wrong planItemInstanceId (typo or from an ended case).

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/3c02d731e6a9f5e0. Report an issue: GitHub.