flowable/flowable-engine · error · FlowableException

Not allowed to access method

Error message

Not allowed to access method ${setterName} on class ${clazz.getCanonicalName()}

What it means

ReflectUtil.getSetter scans a class's methods for a setter matching the given name and value type. If the JVM SecurityManager throws SecurityException during method inspection, it throws this FlowableException naming the setter and class.

Solutions

  1. Grant ReflectPermission (suppressAccessChecks) in your security policy.
  2. Avoid targeting JDK/module-encapsulated classes; use --add-opens for module boundaries you control.
  3. Add a proper public setter to the target class so standard access works without privileged reflection.
  4. Use field injection instead of setter injection if setters are inaccessible.
  5. Run without a restrictive SecurityManager where the platform permits.

Example fix

// before
// class has only package-private setter
void setRecipient(String r) { ... }
// after
public void setRecipient(String r) { this.recipient = r; }
Defensive patterns

Strategy: validation

Validate before calling

boolean hasSetter = java.util.Arrays.stream(clazz.getMethods())
    .anyMatch(m -> m.getName().equalsIgnoreCase("set" + setterName) && m.getParameterCount() == 1);
if (!hasSetter) throw new IllegalStateException("No public setter " + setterName + " on " + clazz.getName());

Try / catch

try {
    Method m = ReflectUtil.getSetter(setterName, clazz, valueType);
} catch (FlowableException e) {
    LOGGER.error("Setter {} blocked on {}: {}", setterName, clazz.getName(), e.getCause());
    throw new SecurityConfigurationException("Grant ReflectPermission or add a public setter", e);
}

Prevention

When it happens

Trigger: Calling getSetter (directly or via invokeSetterOrField / Flowable field injection with setter preference) when a SecurityManager or module access rules deny reflective enumeration/access of the class's declared methods.

Common situations: Strict SecurityManager policies in application servers; reflecting into module-encapsulated or sealed classes on modern JDKs; sandboxed/agent environments restricting setAccessible-equivalent access.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/dd5e6a0d82f2709c. Report an issue: GitHub.

Appendix: source

Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/util/ReflectUtil.java:246

     * Returns the setter-method for the given field name or null if no setter exists.
     */
    public static Method getSetter(String fieldName, Class<?> clazz, Class<?> fieldType) {
        String setterName = "set" + Character.toTitleCase(fieldName.charAt(0)) + fieldName.substring(1);
        try {
            // Using getMethods(), getMethod(...) expects exact parameter type
            // matching and ignores inheritance-tree.
            Method[] methods = clazz.getMethods();
            for (Method method : methods) {
                if (method.getName().equals(setterName)) {
                    Class<?>[] paramTypes = method.getParameterTypes();
                    if (paramTypes != null && paramTypes.length == 1 && paramTypes[0].isAssignableFrom(fieldType)) {
                        return method;
                    }
                }
            }
            return null;
        } catch (SecurityException e) {
            throw new FlowableException("Not allowed to access method " + setterName + " on class " + clazz.getCanonicalName(), e);
        }
    }
    
    public static void invokeSetter(Method setterMethod, Object target, String name, Object value) {
        try {
            setterMethod.invoke(target, value);
        } catch (IllegalArgumentException e) {
            throw new FlowableException("Error while invoking '" + name + "' on class " + target.getClass().getName(), e);
        } catch (IllegalAccessException e) {
            throw new FlowableException("Illegal access when calling '" + name + "' on class " + target.getClass().getName(), e);
        } catch (InvocationTargetException e) {
            throw new FlowableException("Exception while invoking '" + name + "' on class " + target.getClass().getName(), e);
        }
    }

    private static Method findMethod(Class<? extends Object> clazz, String methodName, Object[] args) {
        for (Method method : clazz.getDeclaredMethods()) {
            // TODO add parameter matching

View on GitHub (pinned to d6d39ce1c6)