{"record":{"id":"efb9e13b4d58d84d","repo":"flowable/flowable-engine","slug":"expression","errorCode":null,"errorMessage":"Expression ","messagePattern":"Expression ","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/behavior/impl/ExternalWorkerTaskActivityBehavior.java","lineNumber":105,"sourceCode":"                if (categoryValue != null) {\n                    job.setCategory(categoryValue.toString());\n                }\n        }\n\n        job.setJobType(JobEntity.JOB_TYPE_EXTERNAL_WORKER);\n        job.setRetries(jobServiceConfiguration.getAsyncExecutorNumberOfRetries());\n\n        // Inherit tenant id (if applicable)\n        if (planItemInstanceEntity.getTenantId() != null) {\n            job.setTenantId(planItemInstanceEntity.getTenantId());\n        }\n\n        Expression expression = CommandContextUtil.getExpressionManager(commandContext).createExpression(jobTopicExpression);\n        Object expressionValue = expression.getValue(planItemInstanceEntity);\n        if (expressionValue != null && !expressionValue.toString().isEmpty()) {\n            job.setJobHandlerConfiguration(expressionValue.toString());\n        } else {\n            throw new FlowableException(\"Expression \" + jobTopicExpression + \" did not evaluate to a valid value (non empty String). Was: \" + expressionValue + \". For \" + planItemInstanceEntity);\n        }\n\n        jobService.insertExternalWorkerJob(job);\n\n        if (interceptor != null) {\n            interceptor.afterCreateExternalWorkerJob(new CreateCmmnExternalWorkerJobAfterContext(\n                    serviceTask,\n                    job,\n                    planItemInstanceEntity\n            ));\n        }\n    }\n\n    protected String getJobCategory(BaseElement baseElement) {\n        List<ExtensionElement> jobCategoryElements = baseElement.getExtensionElements().get(\"jobCategory\");\n        if (jobCategoryElements != null && jobCategoryElements.size() > 0) {\n            return jobCategoryElements.get(0).getElementText();\n        }","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/behavior/impl/ExternalWorkerTaskActivityBehavior.java#L87-L123","documentation":"After creating the external worker job, the topic expression is evaluated at runtime; the result must be a non-empty string to become the job's handler configuration. If the expression evaluates to null or the empty string, the engine throws this FlowableException naming the expression, the value, and the plan item.","triggerScenarios":"Expression jobTopicExpression (e.g. ${topicName}) evaluates to null, empty string, or an object whose toString() is empty when the external worker task plan item executes.","commonSituations":"Case variable holding the topic not set before activation; expression resolves to a null-valued data object field; variable name typo; variable set only for some case instances (per-tenant variation).","solutions":["Initialize the topic variable before the external worker task activates (case start variable, form field, or preceding task).","Correct the expression variable name in the case model to match an existing case variable.","Provide a static topic string if the topic does not need to be dynamic.","Add a validation/sentry so the task only activates when the topic variable is non-empty."],"exampleFix":"// before\ncaseRuntimeService.setVariable(caseInstanceId, \"topc\", \"loan-processing\"); // typo -> expression ${topicName} -> null\n// after\ncaseRuntimeService.setVariable(caseInstanceId, \"topicName\", \"loan-processing\");","handlingStrategy":"validation","validationCode":"Object topic = caseVariables.get(\"topicName\");\nif (!(topic instanceof String s) || s.isEmpty()) {\n    throw new IllegalArgumentException(\"topicName variable must be a non-empty string before external worker task activates\");\n}","typeGuard":"if (topicValue instanceof String s && !s.isEmpty()) { /* valid topic */ }","tryCatchPattern":"try {\n    caseRuntimeService.triggerPlanItemInstance(planItemId);\n} catch (FlowableException e) {\n    if (e.getMessage().startsWith(\"Expression \") && e.getMessage().contains(\"did not evaluate to a valid value\")) {\n        log.error(\"Topic expression failed for case {}\", caseInstanceId);\n    }\n    throw e;\n}","preventionTips":["Initialize topic variables at case start","Prefer static topics when the value does not vary per instance","Type-guard dynamic topics: keep them as String variables only"],"tags":["cmmn","external-worker","expression","null-value"],"backgroundTag":"invalid-expression","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}