{"record":{"id":"b4990a4953105a45","repo":"flowable/flowable-engine","slug":"error-function-invocation","errorCode":null,"errorMessage":"error.function.invocation","messagePattern":"error\\.function\\.invocation","errorType":"exception","errorClass":"ELException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/de/odysseus/el/tree/impl/ast/AstFunction.java","lineNumber":123,"sourceCode":"\t\t\t\t\tObject param = getParam(i).eval(bindings, context);\n\t\t\t\t\tif (param != null || types[i].isPrimitive()) {\n\t\t\t\t\t\tparams[i] = bindings.convert(param, types[i]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn method.invoke(base, params);\n\t}\n\n\t@Override \n\tpublic Object eval(Bindings bindings, ELContext context) {\n\t\tMethod method = bindings.getFunction(index);\n\t\ttry {\n\t\t\treturn invoke(bindings, context, null, method);\n\t\t} catch (IllegalAccessException e) {\n\t\t\tthrow new ELException(LocalMessages.get(\"error.function.access\", name), e);\n\t\t} catch (InvocationTargetException e) {\n\t\t\tthrow new ELException(LocalMessages.get(\"error.function.invocation\", name), e.getCause());\n\t\t}\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn name;\n\t}\t\n\n\t@Override \n\tpublic void appendStructure(StringBuilder b, Bindings bindings) {\n\t\tb.append(bindings != null && bindings.isFunctionBound(index) ? \"<fn>\" : name);\n\t\tparams.appendStructure(b, bindings);\n\t}\n\n\t@Override\n\tpublic int getIndex() {\n\t\treturn index;\n\t}","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/de/odysseus/el/tree/impl/ast/AstFunction.java#L105-L141","documentation":"AstFunction.eval() invokes the EL function reflectively; when the invoked method itself throws an exception, it surfaces as InvocationTargetException, and AstFunction rethrows it as ELException with message 'error.function.invocation: <functionName>' and the original cause attached. The EL layer is not failing — your function's code threw.","triggerScenarios":"Evaluating an expression that calls a registered EL function whose implementation throws any runtime/checked exception, e.g. ${myfn:parse(date)} where parse() throws a ParseException or NPE on null input.","commonSituations":"Null or malformed arguments passed to EL functions in process conditions/listeners; function code hitting environmental failures (IO, DB) during expression evaluation; API changes in the function class after a dependency upgrade.","solutions":["Read e.getCause() on the ELException to see the function's original exception and stack trace.","Add defensive checks inside the EL function for null/invalid inputs.","Catch and wrap errors inside the function to produce a domain-specific message.","Test the function directly with the argument values present in the failing expression."],"exampleFix":"// before\npublic static int len(String s) { return s.length(); } // NPE on null\n// after\npublic static int len(String s) { return s == null ? 0 : s.length(); }","handlingStrategy":"try-catch","validationCode":"// smoke-test each registered function with representative args\nObject result = method.invoke(null, sampleArgs); // must not throw","typeGuard":null,"tryCatchPattern":"try {\n    return expr.getValue(context);\n} catch (ELException e) {\n    Throwable cause = e.getCause();\n    log.error(\"EL function failed: {}\", cause, cause);\n    throw new IllegalStateException(\"Function invocation failed: \" + cause.getMessage(), cause);\n}","preventionTips":["Always inspect the ELException cause chain — the real bug is in your function code.","Make EL functions null-safe and input-validating.","Wrap function bodies to convert technical failures into domain errors.","Unit-test functions with the argument shapes used in expressions."],"tags":["el","function-invocation","reflection","wrapped-exception"],"backgroundTag":"upstream-api-error","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"}