{"record":{"id":"dd431070333d95a8","repo":"flowable/flowable-engine","slug":"builder-clazz-is-missing-constructor-can-t-pas","errorCode":null,"errorMessage":"Builder ${clazz} is missing constructor (can't pass features)","messagePattern":"Builder (.+?) is missing constructor \\(can't pass features\\)","errorType":"exception","errorClass":"ELException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/de/odysseus/el/ExpressionFactoryImpl.java","lineNumber":397,"sourceCode":"\t * <code>de.odysseus.el.tree.TreeBuilder</code> interface. If the property is not set, a plain\n\t * <code>de.odysseus.el.tree.impl.Builder</code> is used. If the configured class is a subclass\n\t * of <code>de.odysseus.el.tree.impl.Builder</code> and which provides a constructor taking an\n\t * array of <code>Builder.Feature</code>, this constructor will be invoked. Otherwise, the\n\t * default constructor will be used.\n\t */\n\tprotected TreeBuilder createTreeBuilder(Properties properties, Feature... features) {\n\t\tClass<?> clazz = load(TreeBuilder.class, properties);\n\t\tif (clazz == null) {\n\t\t\treturn createDefaultTreeBuilder(features);\n\t\t}\n\t\ttry {\n\t\t\tif (Builder.class.isAssignableFrom(clazz)) {\n\t\t\t\tConstructor<?> constructor = clazz.getConstructor(Feature[].class);\n\t\t\t\tif (constructor == null) {\n\t\t\t\t\tif (features == null || features.length == 0) {\n\t\t\t\t\t\treturn TreeBuilder.class.cast(clazz.newInstance());\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow new ELException(\"Builder \" + clazz + \" is missing constructor (can't pass features)\");\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\treturn TreeBuilder.class.cast(constructor.newInstance((Object) features));\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn TreeBuilder.class.cast(clazz.newInstance());\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\tthrow new ELException(\"TreeBuilder \" + clazz + \" could not be instantiated\", e);\n\t\t}\n\t}\n\n\tprotected TreeBuilder createDefaultTreeBuilder(Feature... features) {\n\t\treturn new Builder(features);\n\t}\n\n\tprivate Class<?> load(Class<?> clazz, Properties properties) {\n\t\tif (properties != null) {","sourceCodeStart":379,"sourceCodeEnd":415,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/de/odysseus/el/ExpressionFactoryImpl.java#L379-L415","documentation":"createTreeBuilder() checks whether a custom TreeBuilder class implements the Builder interface and, if so, requires a constructor taking Feature[] so configured features can be passed. If getConstructor(Feature[].class) yields no such constructor while features were supplied, it throws ELException 'Builder X is missing constructor (can't pass features)'.","triggerScenarios":"Constructing ExpressionFactoryImpl (e.g. ExpressionFactory.newInstance with Feature options) where the configured TreeBuilder class implements Builder but only declares a no-arg constructor, and at least one Feature is passed.","commonSituations":"Plugging in a custom tree builder written for an older Juel version without the Feature[] constructor; calling newInstance with features (like MethodInvocations or VarArgs) against an incompatible custom builder.","solutions":["Add a public constructor accepting Feature[] to the custom Builder implementation","Construct the factory without features if the builder only supports a no-arg constructor","Use the default Builder (de.odysseus.el.tree.impl.Builder) which supports features"],"exampleFix":"// before\npublic class MyBuilder implements Builder {\n    public MyBuilder() { }\n}\n\n// after\npublic class MyBuilder implements Builder {\n    public MyBuilder() { }\n    public MyBuilder(Feature[] features) { ... }\n}","handlingStrategy":"validation","validationCode":"Class<?> c = Class.forName(\"com.acme.MyBuilder\");\nboolean hasFeatureCtor = Arrays.stream(c.getConstructors())\n    .anyMatch(k -> Arrays.equals(k.getParameterTypes(), new Class[]{Feature[].class}));\nif (hasFeaturesRequested && !hasFeatureCtor) {\n    throw new IllegalStateException(\"Builder implementing Builder interface needs a public Feature[] constructor\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    ExpressionFactory.newInstance(props, features);\n} catch (ELException e) {\n    if (e.getMessage().contains(\"is missing constructor\")) {\n        log.error(\"Add Feature[] constructor to custom Builder or drop features\", e);\n    }\n    throw e;\n}","preventionTips":["Always provide both no-arg and Feature[] constructors on custom Builders","Update custom builders after Juel/JUEL-derived API upgrades","Only pass features when the configured builder supports them"],"tags":["reflection","el","constructor","configuration","flowable"],"backgroundTag":"invalid-constructor-argument","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}