{"record":{"id":"7b77ce7066a52736","repo":"quarkusio/quarkus","slug":"nested-configuration-class-fieldtypeclassinfo","errorCode":null,"errorMessage":"Nested configuration class ' + fieldTypeClassInfo + ' must be public ","messagePattern":"Nested configuration class ' \\+ fieldTypeClassInfo \\+ ' must be public ","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/spring-boot-properties/deployment/src/main/java/io/quarkus/spring/boot/properties/deployment/ClassConfigurationPropertiesUtil.java","lineNumber":331,"sourceCode":"\n                        // we need to register the 'valueOf' method of the enum for reflection because\n                        // that is the method that SmallryeConfig uses for conversion of enums\n                        List<MethodInfo> methods = fieldTypeClassInfo.methods();\n                        for (MethodInfo method : methods) {\n                            if (!method.name().equals(\"valueOf\")) {\n                                continue;\n                            }\n                            if (method.parametersCount() != 1) {\n                                continue;\n                            }\n                            if (method.parameterType(0).name().equals(DotNames.STRING)) {\n                                reflectiveMethods.produce(new ReflectiveMethodBuildItem(getClass().getName(), method));\n                                break;\n                            }\n                        }\n                    } else if (fieldTypeClassInfo.hasNoArgsConstructor()) {\n                        if (!Modifier.isPublic(fieldTypeClassInfo.flags())) {\n                            throw new IllegalArgumentException(\n                                    \"Nested configuration class '\" + fieldTypeClassInfo + \"' must be public \");\n                        }\n\n                        Expr nestedConfigObject = populateConfigObject(classLoader, fieldTypeClassInfo,\n                                getFullConfigName(prefixStr, namingStrategy, field), namingStrategy, failOnMismatchingMember,\n                                null, bc, configParam);\n                        createWriteValue(bc, configObject, field, setter, useFieldAccess, nestedConfigObject);\n                    } else {\n                        LOGGER.warn(\"Nested configuration class '\" + fieldTypeClassInfo\n                                + \"' declared in '\" + currentClassInHierarchy.name() + \".\" + field.name() + \"' is either an \"\n                                + \"interface or does not have a non-args constructor, so this field will not be initialized\");\n                    }\n                } else {\n                    String fullConfigName = getFullConfigName(prefixStr, namingStrategy, field);\n                    if (DotNames.OPTIONAL.equals(fieldTypeDotName)) {\n                        Type genericType = ConfigurationPropertiesUtil.determineSingleGenericType(field.type(),\n                                field.declaringClass().name());\n","sourceCodeStart":313,"sourceCodeEnd":349,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/spring-boot-properties/deployment/src/main/java/io/quarkus/spring/boot/properties/deployment/ClassConfigurationPropertiesUtil.java#L313-L349","documentation":"A field of the configuration properties class is itself a nested configuration object. Nested classes must be instantiable reflectively, and Quarkus requires them to be public; a non-public nested configuration type fails the build.","triggerScenarios":"populateConfigObject encounters a field whose type (fieldTypeClassInfo) has a no-arg constructor and is treated as a nested config object; Modifier.isPublic(fieldTypeClassInfo.flags()) is false, so it throws before recursing into the nested population.","commonSituations":"Package-private inner classes grouping related properties (e.g. AppProps.Security) in migrated Spring Boot apps; default (package) visibility on nested POJOs.","solutions":["Make the nested configuration class public.","If it is an inner class, make it a public static nested class or a public top-level class.","Flatten the nested fields into the parent class if nesting is not required."],"exampleFix":"// before\npublic class AppProps {\n    class Security { private boolean enabled; }\n}\n// after\npublic class AppProps {\n    public static class Security { private boolean enabled;\n        public boolean isEnabled() { return enabled; }\n        public void setEnabled(boolean e) { enabled = e; } }\n}","handlingStrategy":"validation","validationCode":"static void checkNestedConfigPublic(Class<?> props) {\n    for (Field f : props.getDeclaredFields()) {\n        Class<?> t = f.getType();\n        if (!t.isPrimitive() && !t.getName().startsWith(\"java.\") && !Modifier.isPublic(t.getModifiers()))\n            throw new IllegalArgumentException(\"Nested config class \" + t + \" must be public\");\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Declare nested configuration classes public (and static if nested).","Ensure nested classes have public no-arg constructors and setters.","Flatten nested structures when grouping is not essential."],"tags":["quarkus","spring-boot","configuration-properties","nested-config"],"backgroundTag":"nested-config-class-not-public","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}