flowable/flowable-engine · error · ActivitiObjectNotFoundException

execution " + executionId + " doesn't exist

Error message

execution " + executionId + " doesn't exist

What it means

Thrown by NeedsActiveExecutionCmd.execute() when no execution entity exists for the given executionId. The engine looks up the execution via findExecutionById and, since Activiti/Flowable cannot operate on a non-existent execution, it raises ActivitiObjectNotFoundException carrying the expected Execution class. It is a lookup failure, not a state or permission problem.

Solutions

  1. Verify the executionId exists before invoking: create an ExecutionQuery via runtimeService.createExecutionQuery().executionId(id).singleResult() and check for null.
  2. Confirm you are connected to the same process engine/database where the execution lives (check database schema and engine configuration).
  3. Check whether the process instance already completed or was deleted; fetch a fresh executionId from the current process instance instead of a cached one.
  4. Log/correct the source of the id (message correlation, signal payload) to rule out typo or truncation.

Example fix

// before
runtimeService.signal(executionId);

// after
Execution execution = runtimeService.createExecutionQuery().executionId(executionId).singleResult();
if (execution != null) {
    runtimeService.signal(executionId);
}
Defensive patterns

Strategy: validation

Validate before calling

Execution e = runtimeService.createExecutionQuery().executionId(executionId).singleResult();
if (e == null) throw new IllegalArgumentException("execution not found: " + executionId);

Type guard

boolean executionExists(String id) {
    return id != null && runtimeService.createExecutionQuery().executionId(id).singleResult() != null;
}

Try / catch

try {
    runtimeService.signal(executionId);
} catch (ActivitiObjectNotFoundException e) {
    // execution gone; treat as already finished
}

Prevention

When it happens

Trigger: Calling any command extending NeedsActiveExecutionCmd (e.g. signal, message event reception, execution-related runtime operations) with an executionId that has been deleted, was never created, is from a different engine/process instance, or contains a typo.

Common situations: Holding an executionId after the process instance ended and its executions were removed; pointing at an executionId from another process engine or database schema; reusing stale ids cached in application code after a DB cleanup/redeploy of the app.

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/3758246a4cbf1780. Report an issue: GitHub.

Appendix: source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/cmd/NeedsActiveExecutionCmd.java:49

    protected String executionId;

    public NeedsActiveExecutionCmd(String executionId) {
        this.executionId = executionId;
    }

    @Override
    public T execute(CommandContext commandContext) {
        if (executionId == null) {
            throw new ActivitiIllegalArgumentException("executionId is null");
        }

        ExecutionEntity execution = commandContext
                .getExecutionEntityManager()
                .findExecutionById(executionId);

        if (execution == null) {
            throw new ActivitiObjectNotFoundException("execution " + executionId + " doesn't exist", Execution.class);
        }

        if (execution.isSuspended()) {
            throw new ActivitiException(getSuspendedExceptionMessage());
        }

        return execute(commandContext, execution);
    }

    /**
     * Subclasses should implement this method. The provided {@link ExecutionEntity} is guaranteed to be active (ie. not suspended).
     */
    protected abstract T execute(CommandContext commandContext, ExecutionEntity execution);

    /**
     * Subclasses can override this to provide a more detailed exception message that will be thrown when the execution is suspended.
     */
    protected String getSuspendedExceptionMessage() {

View on GitHub (pinned to d6d39ce1c6)