{"record":{"id":"f3318f43d468db49","repo":"flowable/flowable-engine","slug":"illegal-access-when-calling-fieldname-on-class","errorCode":null,"errorMessage":"Illegal access when calling '<fieldName>' on class <className>","messagePattern":"Illegal access when calling '<fieldName>' on class <className>","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/helper/ClassDelegateUtil.java","lineNumber":57,"sourceCode":"\n    public static void applyFieldDeclaration(List<FieldDeclaration> fieldDeclarations, Object target) {\n        if (fieldDeclarations != null) {\n            for (FieldDeclaration declaration : fieldDeclarations) {\n                applyFieldDeclaration(declaration, target);\n            }\n        }\n    }\n\n    public static void applyFieldDeclaration(FieldDeclaration declaration, Object target) {\n        Method setterMethod = ReflectUtil.getSetter(declaration.getName(), 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 FlowableException(\"Error while invoking '\" + declaration.getName() + \"' on class \" + target.getClass().getName(), e);\n            } catch (IllegalAccessException e) {\n                throw new FlowableException(\"Illegal access when calling '\" + declaration.getName() + \"' on class \" + target.getClass().getName(), e);\n            } catch (InvocationTargetException e) {\n                throw new FlowableException(\"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                throw new FlowableIllegalArgumentException(\"Field definition uses non-existing field '\" + declaration.getName() + \"' on class \" + target.getClass().getName());\n            }\n            // Check if the delegate field's type is correct\n            if (!fieldTypeCompatible(declaration, field)) {\n                throw new FlowableIllegalArgumentException(\"Incompatible type set on field declaration '\" + declaration.getName() + \"' for class \" + target.getClass().getName() + \". Declared value has type \"\n                        + declaration.getValue().getClass().getName() + \", while expecting \" + field.getType().getName());\n            }\n            ReflectUtil.setField(field, target, declaration.getValue());\n        }\n    }\n\n    public static boolean fieldTypeCompatible(FieldDeclaration declaration, Field field) {","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/helper/ClassDelegateUtil.java#L39-L75","documentation":"Thrown by ClassDelegateUtil.applyFieldDeclaration when a field-injection setter method invoked reflectively via Method.invoke throws an IllegalAccessException, meaning the setter is not accessible from the calling context (e.g. a non-public setter without setAccessible). Flowable wraps the reflective failure in a FlowableException naming the field and target class.","triggerScenarios":"A BPMN field injection declares a field whose class exposes a setter that is private/protected or otherwise inaccessible, so setterMethod.invoke(target, declaration.getValue()) fails with IllegalAccessException.","commonSituations":"Custom JavaDelegate/service-task classes with non-public setters used with <flowable:field> declarations; class-loader or module access restrictions (JPMS, OSGi) blocking reflection; copying delegate code into a different package and shrinking visibility.","solutions":["Make the injected field's setter method public (and the class public)","Use a public field with direct field injection instead of a setter","Check that no security manager / JPMS module settings block setAccessible on the class","Catch FlowableException in your delegate configuration and log target class + field name to locate the offending setter"],"exampleFix":"// before\npublic class MyDelegate implements JavaDelegate {\n    private void setUrl(String url) { this.url = url; }\n}\n// after\npublic class MyDelegate implements JavaDelegate {\n    private String url;\n    public void setUrl(String url) { this.url = url; }\n}","handlingStrategy":"try-catch","validationCode":"Class<?> c = delegate.getClass();\nfor (FieldDeclaration d : fields) {\n    boolean hasPublicSetter = Arrays.stream(c.getMethods())\n        .anyMatch(m -> m.getName().equals(\"set\" + Character.toUpperCase(d.getName().charAt(0)) + d.getName().substring(1))\n            && Modifier.isPublic(m.getModifiers()));\n    if (!hasPublicSetter) throw new IllegalStateException(\"No public setter for field \" + d.getName());\n}","typeGuard":"static boolean hasAccessibleSetter(Object target, String field) {\n    try { target.getClass().getMethod(\"set\" + Character.toUpperCase(field.charAt(0)) + field.substring(1)); return true; }\n    catch (NoSuchMethodException e) { return false; }\n}","tryCatchPattern":"try { engineService.startProcessInstanceByKey(key, vars); }\ncatch (FlowableException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Illegal access when calling\")) {\n        log.error(\"Field injection setter not accessible: {}\", e.getMessage());\n    } else throw e;\n}","preventionTips":["Always declare injected fields as private with public setters or public visibility","Test delegate field injection in unit tests before deploying processes","Avoid JPMS/security-manager setups that restrict reflection on delegate classes"],"tags":["java","reflection","field-injection","access-modifier"],"backgroundTag":"insufficient-permissions","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"}