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
- Investigate who interrupted the thread (shutdown hook, timeout watchdog) and ensure shutdown sequences drain pending operations before interrupting.
- Increase or configure the max wait timeout on the waiting future so it completes before external interruption.
- Ensure async jobs/async executor are properly started and futures complete; long-pending futures usually mean the async side failed to run.
- 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
- Use bounded future.get timeouts instead of indefinite blocking.
- Shut down executors gracefully, draining pending operations before interrupting threads.
- Keep async jobs healthy so futures complete quickly.
- Preserve and check the interrupt status in custom agenda code.
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
- Future was interrupted
- None of the available futures completed within the max timeo
- Invocation result + invocationResult + from invocation + inv
- Invocation result + invocationResult + from invocation + inv
- Task '
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/469f64e419216239.
Report an issue: GitHub.