flowable/flowable-engine · error · FlowableException
Future was interrupted
Error message
Future was interrupted
What it means
Thrown by WaitForAnyFutureToFinishOperation.run when the thread waiting on futures receives Thread.interrupt(). The interrupt status is restored and rethrown as a FlowableException('Future was interrupted'). This mirrors ExecuteFutureActionOperation's interrupt handling but occurs in the aggregation/waiting operation.
Source
Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/agenda/WaitForAnyFutureToFinishOperation.java:76
} else {
try {
// This blocks until at least one is future is done or the timeout is reached
anyOfFuture.get(timeout.toMillis(), TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
// When the timeout is reached we need to cancel all the futures that are not done
for (ExecuteFutureActionOperation<?> futureOperation : futureOperations) {
if (!futureOperation.isDone()) {
// If there was a timeout then we need to cancel all the futures that have not completed already
futureOperation.getFuture().cancel(true);
}
}
throw new FlowableException("None of the available futures completed within the max timeout of " + timeout, e);
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new FlowableException("Future was interrupted", e);
} catch (ExecutionException e) {
// If there was any exception then it will be handled by the appropriate action
}
// Now go through future operation and schedule them for execution if they are done
for (ExecuteFutureActionOperation<?> futureOperation : futureOperations) {
if (futureOperation.isDone()) {
// If it is done then schedule it for execution
agenda.planOperation(futureOperation);
} else {
// Otherwise plan a new future operation
agenda.planFutureOperation((CompletableFuture<Object>) futureOperation.getFuture(),
(BiConsumer<Object, Throwable>) futureOperation.getAction());
}
}
}
}
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Ensure shutdown hooks complete or cancel pending operations before interrupting worker threads.
- Use bounded future.get timeouts so waits finish naturally instead of relying on interrupts.
- Keep the async executor healthy so futures complete promptly, minimizing the window where interrupts can land.
- Wrap the operation in try-catch of FlowableException and check Thread.currentThread().isInterrupted() to react to cancellation.
Example fix
// before thread.interrupt(); // during pending agenda wait // after operation.getFuture().cancel(false); // cancel the work, not the thread
Defensive patterns
Strategy: try-catch
Try / catch
try {
waitForOperation.run();
} catch (FlowableException e) {
if ("Future was interrupted".equals(e.getMessage())) {
Thread.currentThread().interrupt();
return; // treat as cancellation
}
throw e;
} Prevention
- Cancel individual futures instead of interrupting the executing thread.
- Drain pending operations during shutdown before interrupting workers.
- Use bounded waits so operations finish without needing interrupts.
- Keep async executors responsive to minimize interrupt exposure.
When it happens
Trigger: External interrupt of the executing thread while blocked waiting for future operations (executor shutdown, cancellation, watchdog timeout).
Common situations: Graceful shutdown of the process engine while async waits are pending; container stop/redeploy; timeouts that interrupt worker threads.
Related errors
- Future was interrupted
- None of the available futures completed within the max timeo
- Task '
- Can only enable a plan item instance which is in state ENABL
- Could not lock case instance
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/5800195354b79fd1.
Report an issue: GitHub.