flowable/flowable-engine · warning · 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
FlowableObjectNotFoundException thrown by deleteVariable when the target execution does not have the requested variable in the requested scope (local by default, or global if scope=global). Flowable treats deleting a non-existent variable as a not-found condition and includes the execution id, variable name, and scope in the message. Nothing is deleted when this is thrown.
Solutions
- Verify the variable exists with GET /runtime/process-instances/{id}/variables and check its scope
- Pass ?scope=global if the variable was set on the process instance rather than the local execution
- Check you are using the correct execution id (child executions may hold local variables)
- Handle 404 gracefully and treat it as idempotent deletion in retry/idempotency logic
- Catch FlowableObjectNotFoundException (HTTP 404) around the DELETE call
Example fix
// before
delete(`/runtime/process-instances/${id}/variables/total`)
// after
const vars = await get(`/runtime/process-instances/${id}/variables`);
if (vars.some(v => v.name === 'total')) {
await delete(`/runtime/process-instances/${id}/variables/total`);
} Defensive patterns
Strategy: try-catch
Validate before calling
const vars = await fetch(`/runtime/process-instances/${executionId}/variables`).then(r => r.json());
const exists = vars.some(v => v.name === variableName && (scope ? v.scope === scope : true));
if (!exists) return; // already absent; skip delete Type guard
function variableInScope(v, name, scope) {
return v.name === name && (scope ? v.scope?.toLowerCase() === scope.toLowerCase() : v.scope === 'local');
} Try / catch
try { await deleteVariable(executionId, variableName, scope); } catch (e) { if (e.status === 404) { /* treat as already deleted */ return; } throw e; } Prevention
- GET the variable list and confirm name+scope before deleting
- Remember default scope is local; pass scope=global for process-instance-level variables
- Treat 404 as idempotent success in cleanup jobs
- Check you are targeting the execution that actually owns the variable
When it happens
Trigger: DELETE /runtime/process-instances/{executionId}/variables/{variableName} (optionally ?scope=global|local) where the variable was never set, was already deleted, or exists only in the other scope (e.g. set globally but deleting with default local scope).
Common situations: Race conditions where a concurrent request or process end already removed the variable, deleting a child-execution local variable via the parent execution id, expecting variable inheritance from the process definition (variables are runtime-scoped, not inherited).
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
- Could not find a app model json with id
- Could not find a deployment with id
- Could not find a milestone instance with id
- Could not find a plan item instance with id
- Could not find a resource with id
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/b265b438686e868f.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ExecutionVariableResource.java:198
@ApiOperation(value = "Delete a variable for an execution", tags = { "Executions" }, nickname = "deletedExecutionVariable", code = 204)
@ApiResponses(value = {
@ApiResponse(code = 204, message = "Indicates both the execution and variable were found and variable has been deleted."),
@ApiResponse(code = 404, message = "Indicates the requested execution was not found or the execution does not have a variable with the given name in the requested scope. Status description contains additional information about the error.")
})
@DeleteMapping(value = "/runtime/executions/{executionId}/variables/{variableName}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteVariable(@ApiParam(name = "executionId") @PathVariable("executionId") String executionId, @ApiParam(name = "variableName") @PathVariable("variableName") String variableName,
@RequestParam(value = "scope", required = false) String scope) {
Execution execution = getExecutionFromRequestWithoutAccessCheck(executionId);
// 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(),
VariableInstance.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);
}
}
}
View on GitHub (pinned to d6d39ce1c6)