{"record":{"id":"2283896f10bc3597","repo":"flowable/flowable-engine","slug":"could-not-set-field-field","errorCode":null,"errorMessage":"Could not set field ${field}","messagePattern":"Could not set field (.+?)","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/util/ReflectUtil.java","lineNumber":223,"sourceCode":"        } catch (SecurityException e) {\n            throw new FlowableException(\"not allowed to access field \" + field + \" on class \" + clazz.getCanonicalName(), e);\n        } catch (NoSuchFieldException e) {\n            // for some reason getDeclaredFields doesn't search superclasses\n            // (which getFields() does ... but that gives only public fields)\n            Class<?> superClass = clazz.getSuperclass();\n            if (superClass != null) {\n                return getField(fieldName, superClass);\n            }\n        }\n        return field;\n    }\n\n    public static void setField(Field field, Object object, Object value) {\n        try {\n            field.setAccessible(true);\n            field.set(object, value);\n        } catch (IllegalArgumentException | IllegalAccessException e) {\n            throw new FlowableException(\"Could not set field \" + field, e);\n        }\n    }\n\n    /**\n     * Returns the setter-method for the given field name or null if no setter exists.\n     */\n    public static Method getSetter(String fieldName, Class<?> clazz, Class<?> fieldType) {\n        String setterName = \"set\" + Character.toTitleCase(fieldName.charAt(0)) + fieldName.substring(1);\n        try {\n            // Using getMethods(), getMethod(...) expects exact parameter type\n            // matching and ignores inheritance-tree.\n            Method[] methods = clazz.getMethods();\n            for (Method method : methods) {\n                if (method.getName().equals(setterName)) {\n                    Class<?>[] paramTypes = method.getParameterTypes();\n                    if (paramTypes != null && paramTypes.length == 1 && paramTypes[0].isAssignableFrom(fieldType)) {\n                        return method;\n                    }","sourceCodeStart":205,"sourceCodeEnd":241,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/util/ReflectUtil.java#L205-L241","documentation":"ReflectUtil.setField makes the field accessible and assigns the value. If the JVM rejects the access (IllegalAccessException) or the value's type is not compatible with the field (IllegalArgumentException from Field.set), the failure is wrapped in this FlowableException.","triggerScenarios":"Calling setField(field, object, value) where value's runtime type is not assignable to the field's declared type (e.g. null into a primitive field, wrong object type), or a security/module boundary blocks setAccessible despite it appearing to succeed.","commonSituations":"Field injection in Flowable where expression values resolve to unexpected types; setting null on primitive fields; reflecting into final/static or module-encapsulated fields; JDK upgrades adding module restrictions.","solutions":["Check the cause: IllegalArgumentException → value type incompatible; ensure the value matches the field type (and is non-null for primitives).","Verify the field is not final/static in a way that blocks setting (Field.set on final fields may still fail depending on JDK).","Add --add-opens if the field's package is encapsulated by the module system.","Fix the value passed by the caller (e.g. convert String to int before injection).","Prefer a setter method over raw field reflection when possible."],"exampleFix":"// before\nReflectUtil.setField(retriesField, delegate, null); // int field\n// after\nReflectUtil.setField(retriesField, delegate, 3);","handlingStrategy":"type-guard","validationCode":"if (value == null && field.getType().isPrimitive())\n    throw new IllegalStateException(\"Cannot set null on primitive field \" + field.getName());\nif (value != null && !field.getType().isAssignableFrom(value.getClass()))\n    throw new IllegalStateException(\"Value type \" + value.getClass() + \" not assignable to \" + field.getType());","typeGuard":"static boolean isSettable(Field f, Object v) {\n    if (v == null) return !f.getType().isPrimitive();\n    Class<?> boxed = f.getType().isPrimitive()\n        ? Map.of(int.class, Integer.class, long.class, Long.class, boolean.class, Boolean.class,\n                 double.class, Double.class, float.class, Float.class, short.class, Short.class,\n                 byte.class, Byte.class, char.class, Character.class).getOrDefault(f.getType(), f.getType())\n        : f.getType();\n    return boxed.isAssignableFrom(v.getClass());\n}","tryCatchPattern":"try {\n    ReflectUtil.setField(field, object, value);\n} catch (FlowableException e) {\n    LOGGER.error(\"Set field {} failed: {}\", field, e.getCause().getMessage());\n    throw new IllegalArgumentException(\"Incompatible value for field \" + field.getName(), e);\n}","preventionTips":["Never pass null for primitive fields","Coerce value types (String→int, etc.) before reflective assignment","Avoid final and module-encapsulated fields","Prefer setters or constructor injection over raw field reflection"],"tags":["reflection","field-injection","type-mismatch","java"],"backgroundTag":"type-mismatch","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"}