flowable/flowable-engine · error · FlowableException

Future was interrupted

Error message

Future was interrupted

What it means

Thrown by ExecuteFutureActionOperation.run when Thread.interrupt() is called while the operation is blocked in future.get(). The interrupt status is restored and wrapped in a FlowableException so the engine operation loop can surface the interruption.

Source

Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/agenda/ExecuteFutureActionOperation.java:42

 */
public class ExecuteFutureActionOperation<T> implements Runnable {

    protected final CompletableFuture<T> future;
    protected final BiConsumer<T, Throwable> action;

    public ExecuteFutureActionOperation(CompletableFuture<T> future, BiConsumer<T, Throwable> action) {
        this.future = future;
        this.action = action;
    }

    @Override
    public void run() {
        try {
            T value = future.get();
            action.accept(value, null);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new FlowableException("Future was interrupted", e);
        } catch (CancellationException e) {
            action.accept(null, new FlowableException("Future was canceled", e));
        } catch (ExecutionException e) {
            action.accept(null, e.getCause());
        }
    }

    public boolean isDone() {
        return future.isDone();
    }

    public CompletableFuture<T> getFuture() {
        return future;
    }

    public BiConsumer<T, Throwable> getAction() {
        return action;
    }

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Investigate who interrupted the thread (shutdown hook, timeout watchdog) and ensure shutdown sequences drain pending operations before interrupting.
  2. Increase or configure the max wait timeout on the waiting future so it completes before external interruption.
  3. Ensure async jobs/async executor are properly started and futures complete; long-pending futures usually mean the async side failed to run.
  4. Catch FlowableException in custom command code and check Thread.currentThread().isInterrupted() to handle cancellation gracefully.

Example fix

// before
future.get(); // blocks indefinitely, vulnerable to interrupt
// after
future.get(30, TimeUnit.SECONDS); // bounded wait; handle TimeoutException explicitly
Defensive patterns

Strategy: try-catch

Validate before calling

if (future.isDone() || future.getNow(null) != null) { /* safe to proceed */ }

Try / catch

try {
  executeFutureActionOperation.run();
} catch (FlowableException e) {
  if (e.getCause() instanceof InterruptedException) {
    Thread.currentThread().interrupt(); // propagate cancellation
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Another thread or a timeout mechanism interrupts the thread executing this agenda operation while it waits for an async future to complete (e.g. job executor shutdown, external cancel of a waiting command).

Common situations: Engine/task executor shutdown while async operations are pending; watchdog timeouts interrupting long-running waits; application container redeploy interrupting worker threads.

Related errors


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