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

  1. Ensure the variable used in the topic expression is set with a non-empty value before the task executes
  2. Use a literal topic string instead of an expression if the topic is static, e.g. flowable:topic="myTopic"
  3. Add a default in the expression, e.g. ${topicVar ?: 'defaultTopic'} (SpEL/UEL equivalent) or set it in an execution listener
  4. 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

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


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)