flowable/flowable-engine · error · UnsupportedOperationException
CommandInvoker must be the last interceptor in the chain
Error message
CommandInvoker must be the last interceptor in the chain
What it means
DmnCommandInvoker is the terminal interceptor that executes commands; by design no interceptor may follow it. Its setNext method unconditionally throws UnsupportedOperationException('CommandInvoker must be the last interceptor in the chain') to enforce that invariant during engine command-chain configuration.
Solutions
- Restructure the interceptor chain so DmnCommandInvoker is added last, after all custom interceptors
- In your configurator, call customInterceptor.setNext(...) before wiring the invoker
- Remove any code path that calls setNext on the invoker (it is intentionally unsupported)
- If wrapping all interceptors generically, special-case DmnCommandInvoker and never append after it
Example fix
// before invoker.setNext(customInterceptor); // throws // after customInterceptor.setNext(invoker); // invoker stays last
Defensive patterns
Strategy: fallback
Validate before calling
// in a configurator, assert the invoker is the final link before building
if (!lastInterceptor.equals(invoker)) throw new IllegalStateException("DmnCommandInvoker must terminate the chain"); Try / catch
try { invoker.setNext(next); } catch (UnsupportedOperationException e) { /* reorder: next.setNext(invoker) */ } Prevention
- Always add DmnCommandInvoker last when building interceptor chains
- Never call setNext on the invoker
- Special-case the invoker in generic chain-wrapping code
When it happens
Trigger: Programmatically assembling a DMN engine interceptor chain and calling setNext() on the DmnCommandInvoker instance, or appending it in the middle of a chain via the engine configurator.
Common situations: Custom DmnEngineConfigurationAgenda/interceptor plugins that insert interceptors after the command invoker; copy-pasted chain-building code from process-engine configuration; middleware that wraps all interceptors generically.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- CommandInvoker must be the last interceptor in the chain
- Behavior is not supported for a case task for
- can't clear configuration beans
- can't clear configuration beans
- can't search values in configuration beans
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/2307a28f8372370e.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-dmn-engine/src/main/java/org/flowable/dmn/engine/impl/interceptor/DmnCommandInvoker.java:134
protected void executeExecutionListenersAfterException(CommandContext commandContext, Runnable runnable, Throwable throwable) {
if (agendaOperationExecutionListeners != null && !agendaOperationExecutionListeners.isEmpty()) {
for (AgendaOperationExecutionListener listener : agendaOperationExecutionListeners) {
listener.afterExecuteException(commandContext, runnable, throwable);
}
}
}
protected void executeOperation(CommandContext commandContext, Runnable runnable) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Executing agenda operation {}", runnable);
}
runnable.run();
}
@Override
public void setNext(CommandInterceptor next) {
throw new UnsupportedOperationException("CommandInvoker must be the last interceptor in the chain");
}
}
View on GitHub (pinned to d6d39ce1c6)