flowable/flowable-engine · error · ActivitiException
${exc.getMessage()}
Error message
${exc.getMessage()} What it means
In ServiceTaskDelegateExpressionActivityBehavior.execute, when the delegate throws an exception that is not a BpmnError (so no error can be propagated), the engine re-throws it as an ActivitiException whose message is the original exception's message, keeping the original as the cause. It is a generic re-wrap of delegate failures.
Solutions
- Read the 'Caused by' chain for the real exception thrown by the delegate and fix it there
- Throw BpmnError from the delegate for business errors so ErrorPropagation can route to error boundary events
- Add null-safe message handling/logging in the delegate to avoid 'null' messages
- Wrap risky delegate logic (network, parsing) with explicit checks before throwing
Example fix
// before (delegate)
public void execute(DelegateExecution e) {
callRemote((String) e.getVariable("url")); // NPE if url is null
}
// after
public void execute(DelegateExecution e) {
String url = (String) e.getVariable("url");
if (url == null) {
throw new BpmnError("MISSING_URL", "process variable 'url' is required");
}
callRemote(url);
} Defensive patterns
Strategy: try-catch
Validate before calling
String url = (String) execution.getVariable("url");
if (url == null || url.isEmpty()) {
throw new BpmnError("MISSING_URL");
} Try / catch
try {
taskService.complete(taskId);
} catch (org.activiti.engine.ActivitiException e) {
Throwable c = e.getCause();
// inspect root cause; if business error, route to error handling
} Prevention
- Null-check every process variable consumed by the delegate
- Throw BpmnError from delegates for business errors so ErrorPropagation can catch them
- Ensure thrown exceptions carry descriptive messages (this wrapper's message mirrors the cause's)
- Add a wait-state/error boundary event around service tasks that call external systems
When it happens
Trigger: A delegate resolved via delegateExpression throws a non-BpmnError exception whose walk-back through getCause() finds no BpmnError; e.g. a JavaDelegate's execute() throws RuntimeException, IOException, or NPE during task execution.
Common situations: Delegates failing on null process variables, network/DB errors inside the delegate, class-cast issues when reading variables; message may be null when the underlying exception has no message, making logs confusing.
Related errors
- Delegate expression did neither resolve to an…
- ${exc.getMessage()}
- Exception while invoking TaskListener
- Could not execute inner activity behavior of multi instance…
- Could not execute shell command for + execution
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/583213b8f18895d7.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/behavior/ServiceTaskDelegateExpressionActivityBehavior.java:133
Throwable cause = exc;
BpmnError error = null;
while (cause != null) {
if (cause instanceof BpmnError) {
error = (BpmnError) cause;
break;
} else if (cause instanceof RuntimeException) {
if (ErrorPropagation.mapException((RuntimeException) cause, activityExecution, mapExceptions)) {
return;
}
}
cause = cause.getCause();
}
if (error != null) {
ErrorPropagation.propagateError(error, activityExecution);
} else {
throw new ActivitiException(exc.getMessage(), exc);
}
}
}
}
View on GitHub (pinned to d6d39ce1c6)