quarkusio/quarkus · error · IllegalArgumentException

Configuration properties class '' + configClassInfo + '' doe

Error message

Configuration properties class '' + configClassInfo + '' does not have a setter for field ' + field.name() + ' nor is the field a public non-final field.

What it means

Every property field of a Spring-style @ConfigurationProperties class must be bindable: either via a setter or via a public non-final field. When neither exists, the build fails if failOnMismatchingMember is true; otherwise the member is skipped with a warning.

Source

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

                    if ((configPropertyDefaultValue != null)
                            && !configPropertyDefaultValue.asString().equals(ConfigProperty.UNCONFIGURED_VALUE)) {
                        LOGGER.warn(
                                "'defaultValue' of '@ConfigProperty' is ignored when added to a field of a class annotated with '@ConfigProperties'. Offending field is '"
                                        + field.name() + "' of class '" + field.declaringClass().toString() + "'");
                    }
                }
                boolean useFieldAccess = false;

                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());

View on GitHub (pinned to e1c734241f)

Solutions

  1. Add a public setter (setFieldName) for each bound field.
  2. Or make the field public and non-final so field access is used.
  3. Set quarkus.spring-config-properties.fail-on-mismatching-member=false only if you accept the field being ignored with a warning.

Example fix

// before
@ConfigurationProperties("app")
public class AppProps {
    public final String name = "x"; // public final: rejected
}
// after
@ConfigurationProperties("app")
public class AppProps {
    private String name;
    public void setName(String name) { this.name = name; }
}
Defensive patterns

Strategy: validation

Validate before calling

static void checkBindable(Class<?> props) {
    for (Field f : props.getDeclaredFields()) {
        if (Modifier.isStatic(f.getModifiers())) continue;
        boolean hasSetter = Arrays.stream(props.getMethods())
                .anyMatch(m -> m.getName().equals("set" + capitalize(f.getName()))
                        && m.getParameterCount() == 1);
        boolean publicNonFinal = Modifier.isPublic(f.getModifiers()) && !Modifier.isFinal(f.getModifiers());
        if (!hasSetter && !publicNonFinal)
            throw new IllegalArgumentException("Field " + f.getName() + " in " + props + " is not bindable");
    }
}

Prevention

When it happens

Trigger: populateConfigObject iterates each field of the config class; when no setter method is found and the field is private, or public but final, it throws IllegalArgumentException (strict mode) or logs a warning and skips the field.

Common situations: Spring Boot classes relying on constructor binding (no setters, final fields) migrated to Quarkus; fields renamed without updating accessors; immutable value-style config classes.

Related errors


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