flowable/flowable-engine · error · FlowableException
Expression did not evaluate to a valid value (non empty…
Error message
Expression ${jobTopicExpression} did not evaluate to a valid value (non empty String). Was: ${topicValue} What it means
ExternalWorkerTaskActivityBehavior.execute() evaluates the job's topic expression and sets it as the job handler configuration. If the expression returns null or an empty string, the external worker job would have no topic, so it throws FlowableException with the expression and the evaluated value.
Solutions
- Ensure the variable used in the topic expression is set with a non-empty value before the task executes
- Use a literal topic string instead of an expression if the topic is static, e.g. flowable:topic="myTopic"
- Add a default in the expression, e.g. ${topicVar ?: 'defaultTopic'} (SpEL/UEL equivalent) or set it in an execution listener
- Validate the input data feeding the topic variable at process start
Example fix
// before
<serviceTask id="ext" flowable:type="external-worker" flowable:topic="${missingVar}"/>
// after
<serviceTask id="ext" flowable:type="external-worker" flowable:topic="my-topic"/> Defensive patterns
Strategy: validation
Validate before calling
Object topic = execution.getVariable("topicVar");
if (topic == null || topic.toString().isEmpty()) throw new IllegalStateException("topic must be non-empty before external worker task"); Try / catch
try { /* advance to external worker task */ }
catch (FlowableException e) { if (e.getMessage().contains("did not evaluate to a valid value")) { fixTopicVariable(); } throw e; } Prevention
- Set topic variables before reaching the task (e.g. in an execution listener)
- Use literal topics when the topic is static
- Validate inputs at process start
When it happens
Trigger: A service task of type 'external worker' has a flowable:topic expression that evaluates to null or "" at runtime, e.g. ${topicVar} where topicVar is unset.
Common situations: Topic variable never initialized before the task; expression referencing a misspelled variable; expression built from request data that was empty.
Related errors
- Can only complete BPMN external job with a BPMN error. Job…
- Can only terminate CMMN external job. Job with id
- Cannot complete BPMN job. There is no BPMN engine available
- Cannot query external jobs. There is no BPMN or CMMN engine…
- Category expression does not resolve to a string
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/b4d102c97e1c7b80.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/behavior/ExternalWorkerTaskActivityBehavior.java:124
job.setRetries(jobServiceConfiguration.getAsyncExecutorNumberOfRetries());
// Inherit tenant id (if applicable)
if (execution.getTenantId() != null) {
job.setTenantId(execution.getTenantId());
}
Expression jobTopicExpression;
if (StringUtils.isEmpty(beforeContext.getJobTopicExpression())) {
jobTopicExpression = this.jobTopicExpression;
} else {
jobTopicExpression = processEngineConfiguration.getExpressionManager()
.createExpression(beforeContext.getJobTopicExpression());
}
Object topicValue = jobTopicExpression.getValue(execution);
if (topicValue != null && !topicValue.toString().isEmpty()) {
job.setJobHandlerConfiguration(topicValue.toString());
} else {
throw new FlowableException("Expression " + jobTopicExpression + " did not evaluate to a valid value (non empty String). Was: " + topicValue);
}
jobService.insertExternalWorkerJob(job);
if (interceptor != null) {
interceptor.afterCreateExternalWorkerJob(new CreateExternalWorkerJobAfterContext(
(ExternalWorkerServiceTask) currentFlowElement,
job,
execution
));
}
} else {
leave((ActivityExecution) execution);
}
}
@Override
public void signal(ActivityExecution execution, String signalName, Object data) {View on GitHub (pinned to d6d39ce1c6)