{"record":{"id":"f8913f095533f28c","repo":"flowable/flowable-engine","slug":"condition-expression-returns-non-boolean-sequence","errorCode":null,"errorMessage":"condition expression returns non-Boolean (sequenceFlowId: ${sequenceFlowId}): ${result} (${result.getClass().getName()})","messagePattern":"condition expression returns non-Boolean \\(sequenceFlowId: (.+?)\\): (.+?) \\((.+?)\\)","errorType":"exception","errorClass":"ActivitiException","httpStatus":null,"severity":"error","filePath":"modules/flowable5-engine/src/main/java/org/activiti/engine/impl/el/UelExpressionCondition.java","lineNumber":59,"sourceCode":"\n    @Override\n    public boolean evaluate(String sequenceFlowId, DelegateExecution execution) {\n        String conditionExpression = null;\n        if (Context.getProcessEngineConfiguration().isEnableProcessDefinitionInfoCache()) {\n            ObjectNode elementProperties = Context.getBpmnOverrideElementProperties(sequenceFlowId, execution.getProcessDefinitionId());\n            conditionExpression = getActiveValue(initialConditionExpression, DynamicBpmnConstants.SEQUENCE_FLOW_CONDITION, elementProperties);\n        } else {\n            conditionExpression = initialConditionExpression;\n        }\n\n        Expression expression = Context.getProcessEngineConfiguration().getExpressionManager().createExpression(conditionExpression);\n        Object result = expression.getValue(execution);\n\n        if (result == null) {\n            throw new ActivitiException(\"condition expression returns null (sequenceFlowId: \" + sequenceFlowId + \")\" );\n        }\n        if (!(result instanceof Boolean)) {\n            throw new ActivitiException(\"condition expression returns non-Boolean (sequenceFlowId: \" + sequenceFlowId + \"): \" + result + \" (\" + result.getClass().getName() + \")\");\n        }\n        return (Boolean) result;\n    }\n\n    protected String getActiveValue(String originalValue, String propertyName, ObjectNode elementProperties) {\n        String activeValue = originalValue;\n        if (elementProperties != null) {\n            JsonNode overrideValueNode = elementProperties.get(propertyName);\n            if (overrideValueNode != null) {\n                if (overrideValueNode.isNull()) {\n                    activeValue = null;\n                } else {\n                    activeValue = overrideValueNode.asString();\n                }\n            }\n        }\n        return activeValue;\n    }","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable5-engine/src/main/java/org/activiti/engine/impl/el/UelExpressionCondition.java#L41-L77","documentation":"After evaluation, UelExpressionCondition type-checks the result: a sequence-flow condition must yield a Boolean. Any non-Boolean value (String, Integer, etc.) throws ActivitiException naming the flow id, the value and its class.","triggerScenarios":"A conditionExpression returning a truthy non-boolean, e.g. ${status} where status is \"active\", or a numeric/string expression used as a gateway condition.","commonSituations":"Migrating from engines/versions with looser condition typing; using string comparisons that return the string rather than a comparison; calling methods that return Object.","solutions":["Rewrite the condition to a boolean expression, e.g. ${status == 'active'} instead of ${status}","Make the invoked bean method return boolean/Boolean","Declare the variable type properly and use comparison operators in the condition"],"exampleFix":"// before\n<conditionExpression xsi:type=\"tFormalExpression\">${status}</conditionExpression>\n// after\n<conditionExpression xsi:type=\"tFormalExpression\">${status == 'active'}</conditionExpression>","handlingStrategy":"validation","validationCode":"Object r = expression.getValue(execution);\nif (!(r instanceof Boolean)) {\n    throw new IllegalArgumentException(\"Condition must be Boolean, got: \"\n        + (r == null ? \"null\" : r.getClass().getName()));\n}","typeGuard":"boolean isBooleanCondition(Object r) {\n    return r instanceof Boolean;\n}","tryCatchPattern":"try {\n    condition.evaluate(execution, sequenceFlowId);\n} catch (ActivitiException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"non-Boolean\")) {\n        // rewrite expression with comparison operator\n    }\n}","preventionTips":["Use comparison operators (==, !=, <) in gateway conditions rather than raw variable values","Type condition-producing bean methods as boolean","Review BPMN conditions after engine migrations for typing changes"],"tags":["expression-language","condition","gateway","type-mismatch"],"backgroundTag":"type-mismatch","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-18T11:17:12.947Z"}