quarkusio/quarkus · error · IllegalArgumentException

Setter '' + setterName + '' of class '' + configClassInfo +

Error message

Setter '' + setterName + '' of class '' + configClassInfo + '' must be public

What it means

When a setter method exists for a configuration field but is not public, the framework cannot invoke it reflectively at build time to populate the config object. Non-public setters are therefore rejected with this IllegalArgumentException.

Source

Thrown at extensions/spring-boot-properties/deployment/src/main/java/io/quarkus/spring/boot/properties/deployment/ClassConfigurationPropertiesUtil.java:298

                String setterName = JavaBeanUtil.getSetterName(field.name());
                Type fieldType = field.type();
                MethodInfo setter = currentClassInHierarchy.method(setterName, fieldType);
                if (setter == null) {
                    if (!Modifier.isPublic(field.flags()) || Modifier.isFinal(field.flags())) {
                        String message = "Configuration properties class '" + configClassInfo
                                + "' does not have a setter for field '"
                                + field.name() + "' nor is the field a public non-final field.";
                        if (failOnMismatchingMember) {
                            throw new IllegalArgumentException(message);
                        } else {
                            LOGGER.warn(message + " It will therefore be ignored.");
                            continue;
                        }
                    }
                    useFieldAccess = true;
                }
                if (!useFieldAccess && !Modifier.isPublic(setter.flags())) {
                    throw new IllegalArgumentException(
                            "Setter '" + setterName + "' of class '" + configClassInfo + "' must be public");
                }

                /*
                 * If the object is part of the application we are dealing with a nested object
                 * What we do is simply recursively build it up based by adding the field name to the config name prefix
                 */
                DotName fieldTypeDotName = fieldType.name();
                ClassInfo fieldTypeClassInfo = applicationIndex.getClassByName(fieldType.name());
                if (fieldTypeClassInfo != null) {
                    if (DotNames.ENUM.equals(fieldTypeClassInfo.superName())) {
                        populateTypicalProperty(bc, configObject, configPropertyBuildItemCandidates,
                                currentClassInHierarchy, field, useFieldAccess, fieldType, setter, configParam,
                                getFullConfigName(prefixStr, namingStrategy, field));

                        // we need to register the 'valueOf' method of the enum for reflection because
                        // that is the method that SmallryeConfig uses for conversion of enums
                        List<MethodInfo> methods = fieldTypeClassInfo.methods();

View on GitHub (pinned to e1c734241f)

Solutions

  1. Make the setter method public.
  2. Alternatively make the field public non-final so field access is used instead of the setter.
  3. Rename the accessor if it is not actually intended as the bound setter.

Example fix

// before
void setName(String name) { this.name = name; }
// after
public void setName(String name) { this.name = name; }
Defensive patterns

Strategy: validation

Validate before calling

static void checkPublicSetters(Class<?> props) {
    for (Method m : props.getDeclaredMethods()) {
        if (m.getName().startsWith("set") && m.getParameterCount() == 1
                && !Modifier.isPublic(m.getModifiers()))
            throw new IllegalArgumentException(m + " must be public");
    }
}

Prevention

When it happens

Trigger: populateConfigObject resolves the setter for a field and, when useFieldAccess is false, checks Modifier.isPublic(setter.flags()); a protected/package-private/private setter triggers the throw.

Common situations: Fluent setters returning 'this' made package-private; setters narrowed to protected for subclass-only access during refactoring; generated classes with restricted accessors.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/14a3e2fef0cdd5fb. Report an issue: GitHub.