flowable/flowable-engine · error · FlowableObjectNotFoundException

No process instance found for id ''

Error message

No process instance found for id ''

What it means

ExecutionEntityManagerImpl.deleteProcessInstance looks up the process instance execution by id before cascading a delete. When findById returns null (no execution with that id exists, or the id points to a non-process-instance execution that cannot be loaded), it throws FlowableObjectNotFoundException with ProcessInstance.class. This is Flowable's not-found signal for runtimeService.deleteProcessInstance().

Solutions

  1. Check existence first: runtimeService.createProcessInstanceQuery().processInstanceId(id).count() before deleting, and skip when 0.
  2. Catch FlowableObjectNotFoundException around deleteProcessInstance and treat it as already-deleted/idempotent.
  3. Verify the id is a process-instance execution id (root execution), not an inner execution/task id.
  4. Fix concurrency: serialize cancel/complete operations or re-check state after a FlowableOptimisticLocking/NotFound failure.

Example fix

// before
runtimeService.deleteProcessInstance(instanceId, "cleanup");

// after
if (runtimeService.createProcessInstanceQuery()
        .processInstanceId(instanceId).count() > 0) {
    runtimeService.deleteProcessInstance(instanceId, "cleanup");
}
Defensive patterns

Strategy: validation

Validate before calling

if (runtimeService.createProcessInstanceQuery()
        .processInstanceId(instanceId).count() == 0) {
    return; // nothing to delete
}

Try / catch

try {
    runtimeService.deleteProcessInstance(instanceId, reason);
} catch (FlowableObjectNotFoundException e) {
    // already gone: treat as idempotent success
}

Prevention

When it happens

Trigger: Calling runtimeService.deleteProcessInstance(processInstanceId, reason) with an id that never existed, was mistyped, or whose instance already ended (suspended/completed/cancelled and removed from ACT_RU_EXECUTION); deleting concurrently from another thread/job so the instance is gone by the time this runs.

Common situations: Batch cleanup scripts hitting already-completed instances; user-supplied instance ids not validated; race between a timeout/cancel job and a user completing the instance; environments cleaned by history-level cleanup while ids are kept in a UI.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/persistence/entity/ExecutionEntityManagerImpl.java:455

            getHistoryManager().recordDeleteHistoricProcessInstancesByProcessDefinitionId(processDefinitionId);
        }
    }
    
    @Override
    public void deleteProcessInstance(String processInstanceId, String deleteReason, boolean cascade) {
        deleteProcessInstance(processInstanceId, deleteReason, cascade, false);
    }
    
    @Override
    public void deleteProcessInstance(String processInstanceId, String deleteReason, boolean cascade, boolean directDeleteInDatabase) {
        ExecutionEntity processInstanceExecution = findById(processInstanceId);

        if (engineConfiguration.getEndProcessInstanceInterceptor() != null) {
            engineConfiguration.getEndProcessInstanceInterceptor().beforeEndProcessInstance(processInstanceExecution, ProcessInstanceState.CANCELLED);
        }

        if (processInstanceExecution == null) {
            throw new FlowableObjectNotFoundException("No process instance found for id '" + processInstanceId + "'", ProcessInstance.class);
        }

        deleteProcessInstanceCascade(processInstanceExecution, ProcessInstanceState.CANCELLED, deleteReason, cascade, directDeleteInDatabase);
        
        // Special care needed for a process instance of a call activity: the parent process instance needs to be triggered for completion
        // This can't be added to the deleteProcessInstanceCascade method, as this will also trigger all child and/or multi-instance
        // process instances for child call activities, which shouldn't happen.
        if (processInstanceExecution.getSuperExecutionId() != null) {
            ExecutionEntity superExecution = processInstanceExecution.getSuperExecution();
            if (superExecution != null
                    && superExecution.getCurrentFlowElement() instanceof FlowNode flowNode
                    && flowNode.getBehavior() instanceof SubProcessActivityBehavior subProcessActivityBehavior) {
                try {
                    subProcessActivityBehavior.completing(superExecution, processInstanceExecution);
                    superExecution.setSubProcessInstance(null);
                    subProcessActivityBehavior.completed(superExecution);
                } catch (Exception e) {
                    throw new FlowableException("Could not complete parent process instance for call activity with process instance execution " 

View on GitHub (pinned to d6d39ce1c6)