{"record":{"id":"3a31739542891129","repo":"quarkusio/quarkus","slug":"class-s-which-is-used-as-s-in-class-s-must-3a3173","errorCode":null,"errorMessage":"Class '%s' which is used as %s in class '%s' must be a public class","messagePattern":"Class '(.+?)' which is used as (.+?) in class '(.+?)' must be a public class","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/spring-boot-properties/deployment/src/main/java/io/quarkus/spring/boot/properties/deployment/YamlListObjectHandler.java","lineNumber":211,"sourceCode":"                    });\n                });\n            }\n        });\n    }\n\n    private void validateClass(ClassInfo classInfo, Member member) {\n        if (Modifier.isInterface(classInfo.flags())) {\n            throw new IllegalArgumentException(\n                    \"The use of interfaces as the generic type of Lists fields / methods is not allowed. Offending field is '\"\n                            + member.name() + \"' of class '\" + member.declaringClass().name().toString() + \"'\");\n        }\n        if (!classInfo.hasNoArgsConstructor()) {\n            throw new IllegalArgumentException(\n                    String.format(\"Class '%s' which is used as %s in class '%s' must have a no-args constructor\", classInfo,\n                            member.phraseUsage(), member.declaringClass().name().toString()));\n        }\n        if (!Modifier.isPublic(classInfo.flags())) {\n            throw new IllegalArgumentException(\n                    String.format(\"Class '%s' which is used as %s in class '%s' must be a public class\", classInfo,\n                            member.phraseUsage(), member.declaringClass().name().toString()));\n        }\n    }\n\n    private ClassInfo validateType(Type type) {\n        if (type.kind() != Type.Kind.PARAMETERIZED_TYPE) {\n            throw new IllegalArgumentException(ILLEGAL_ARGUMENT_MESSAGE);\n        }\n        ParameterizedType parameterizedType = (ParameterizedType) type;\n        if (!DotNames.LIST.equals(parameterizedType.name())) {\n            throw new IllegalArgumentException(ILLEGAL_ARGUMENT_MESSAGE);\n        }\n        if (parameterizedType.arguments().size() != 1) {\n            throw new IllegalArgumentException(ILLEGAL_ARGUMENT_MESSAGE);\n        }\n        ClassInfo classInfo = index.getClassByName(parameterizedType.arguments().get(0).name());\n        if (classInfo == null) {","sourceCodeStart":193,"sourceCodeEnd":229,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/spring-boot-properties/deployment/src/main/java/io/quarkus/spring/boot/properties/deployment/YamlListObjectHandler.java#L193-L229","documentation":"Thrown by YamlListObjectHandler.validateClass when a class used as a nested Spring Boot properties type fails the public-visibility check. The handler supports deserializing spring-boot-properties YAML structures including generic list element types; the reflective/codegen binding path requires the element class (used as <member> in class <declaring class>) to be instantiable, so non-public classes (and interfaces and classes without no-arg constructors, checked by sibling guards) are rejected at build time.","triggerScenarios":"A List<SomeClass> config member where SomeClass is package-private, protected, or private (e.g. a nested class without the public modifier) in a @ConfigProperties-processed class.","commonSituations":"Nested helper classes inside config classes declared without 'public', common when the nested class is only used internally.","solutions":["Mark the element class public (for nested classes: public static class ...)","Move the class to its own top-level public file","Use a @ConfigMapping interface instead of class-based config"],"exampleFix":"// before\nclass ServerConfig { ... }\n// after\npublic class ServerConfig { ... }","handlingStrategy":"validation","validationCode":"static void requirePublicClass(Class<?> c) {\n    if (!java.lang.reflect.Modifier.isPublic(c.getModifiers()))\n        throw new IllegalStateException(c + \" must be public for YAML config binding\");\n}","typeGuard":"boolean isPublicConcrete(Class<?> c) {\n    return java.lang.reflect.Modifier.isPublic(c.getModifiers()) && !c.isInterface();\n}","tryCatchPattern":"catch (IllegalArgumentException e) { if (e.getMessage().contains(\"must be a public class\")) { /* make class public */ } throw e; }","preventionTips":["Declare config element classes public (public static nested classes)","Review visibility when extracting nested config helper classes"],"tags":["quarkus","yaml","config","visibility"],"backgroundTag":"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"}