{"record":{"id":"f584de52c7eb1893","repo":"flowable/flowable-engine","slug":"exception-while-invoking-s-on-class-s","errorCode":null,"errorMessage":"Exception while invoking '%s' on class %s","messagePattern":"Exception while invoking '(.+?)' on class (.+?)","errorType":"exception","errorClass":"ActivitiException","httpStatus":null,"severity":"error","filePath":"modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/helper/ClassDelegate.java","lineNumber":275,"sourceCode":"    }\n\n    public static void applyFieldDeclaration(FieldDeclaration declaration, Object target) {\n        applyFieldDeclaration(declaration, target, true);\n    }\n\n    public static void applyFieldDeclaration(FieldDeclaration declaration, Object target, boolean throwExceptionOnMissingField) {\n        Method setterMethod = ReflectUtil.getSetter(declaration.getName(),\n                target.getClass(), declaration.getValue().getClass());\n\n        if (setterMethod != null) {\n            try {\n                setterMethod.invoke(target, declaration.getValue());\n            } catch (IllegalArgumentException e) {\n                throw new ActivitiException(\"Error while invoking '\" + declaration.getName() + \"' on class \" + target.getClass().getName(), e);\n            } catch (IllegalAccessException e) {\n                throw new ActivitiException(\"Illegal access when calling '\" + declaration.getName() + \"' on class \" + target.getClass().getName(), e);\n            } catch (InvocationTargetException e) {\n                throw new ActivitiException(\"Exception while invoking '\" + declaration.getName() + \"' on class \" + target.getClass().getName(), e);\n            }\n        } else {\n            Field field = ReflectUtil.getField(declaration.getName(), target);\n            if (field == null) {\n                if (throwExceptionOnMissingField) {\n                    throw new ActivitiIllegalArgumentException(\"Field definition uses unexisting field '\" + declaration.getName() + \"' on class \" + target.getClass().getName());\n                } else {\n                    return;\n                }\n            }\n\n            // Check if the delegate field's type is correct\n            if (!fieldTypeCompatible(declaration, field)) {\n                throw new ActivitiIllegalArgumentException(\"Incompatible type set on field declaration '\" + declaration.getName()\n                        + \"' for class \" + target.getClass().getName()\n                        + \". Declared value has type \" + declaration.getValue().getClass().getName()\n                        + \", while expecting \" + field.getType().getName());\n            }","sourceCodeStart":257,"sourceCodeEnd":293,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/helper/ClassDelegate.java#L257-L293","documentation":"If the setter itself throws an exception while being invoked reflectively, Method.invoke wraps it in InvocationTargetException. ClassDelegate unwraps the situation into this ActivitiException ('Exception while invoking ...'), preserving the cause, since a failing setter means the delegate cannot be initialized safely.","triggerScenarios":"The delegate's setter (matched by name for the activiti:field declaration) throws any RuntimeException/Error during injection - e.g. parsing a bad value, NPE on a dependency, validation inside the setter.","commonSituations":"Setter performs Integer.parseInt/format conversions on injected strings and the XML value is malformed; setter eagerly connects to a resource (DB/queue) that is down; setter asserts configuration validity and fails on bad process config.","solutions":["Read the cause chain (getCause() of the ActivitiException) to find the original exception inside the setter and fix that logic/value.","Make the setter defensive: validate/convert the injected value and fail with a clear message.","Correct the field value in the BPMN XML or Spring config so the setter succeeds."],"exampleFix":"// before\npublic void setRatio(String ratio) { this.ratio = Integer.parseInt(ratio); } // throws on \"0.5\"\n// after\npublic void setRatio(String ratio) { this.ratio = Double.parseDouble(ratio); }","handlingStrategy":"try-catch","validationCode":"// smoke-test the setter before deployment:\nnew DelegateClass().setMyField(testValue); // should not throw for valid config values","typeGuard":"null","tryCatchPattern":"try {\n  applyFieldDeclaration(declaration, target, throwExceptionOnMissingField);\n} catch (ActivitiException e) {\n  if (e.getMessage().startsWith(\"Exception while invoking\")) {\n    Throwable root = e.getCause(); // original setter failure\n    log.error(\"Setter {} threw {}\", declaration.getName(), root, e);\n  } else throw e;\n}","preventionTips":["Keep setters simple: assign and defer heavy logic to execute()","Never open connections or parse brittle values inside setters","Log and validate injected values at the top of execute()"],"tags":["reflection","field-injection","delegate","setter-exception"],"backgroundTag":"invalid-config-value","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"}