{"record":{"id":"1abb8f359be32998","repo":"apache/dubbo","slug":"cannot-assign-nested-class-when-refreshing-config","errorCode":null,"errorMessage":"Cannot assign nested class when refreshing config: <className>","messagePattern":"Cannot assign nested class when refreshing config: <className>","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java","lineNumber":932,"sourceCode":"                // if mode is others, override with new map\n                if (overrideIfAbsent) {\n                    newMap.putAll(oldMap);\n                } else if (overrideAll) {\n                    oldMap.forEach(newMap::putIfAbsent);\n                }\n\n                invokeSetParameters(newMap, obj);\n            } else if (isNestedSetter(obj, method)) {\n                try {\n                    Class<?> clazz = method.getParameterTypes()[0];\n                    Object inner = clazz.getDeclaredConstructor().newInstance();\n                    String fieldName = MethodUtils.extractFieldName(method);\n                    Map<String, String> subProperties = ConfigurationUtils.getSubProperties(properties, fieldName);\n                    InmemoryConfiguration subPropsConfiguration = new InmemoryConfiguration(subProperties);\n                    assignProperties(inner, environment, subProperties, subPropsConfiguration, configMode);\n                    method.invoke(obj, inner);\n                } catch (ReflectiveOperationException e) {\n                    throw new IllegalStateException(\n                            \"Cannot assign nested class when refreshing config: \"\n                                    + obj.getClass().getName(),\n                            e);\n                }\n            }\n        }\n    }\n\n    private boolean isPropertySet(List<Method> methods, String propertyName) {\n        try {\n            String getterName = calculatePropertyToGetter(propertyName);\n            Method getterMethod = findGetMethod(methods, getterName);\n            if (getterMethod == null) {\n                return false;\n            }\n            Object oldOne = getterMethod.invoke(this);\n            if (oldOne != null) {\n                return true;","sourceCodeStart":914,"sourceCodeEnd":950,"githubUrl":"https://github.com/apache/dubbo/blob/3a3043227f5571d25eb2889de5bca22f2914843b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java#L914-L950","documentation":"Thrown by AbstractConfig.assignProperties on the nested-setter branch: while refreshing, Dubbo instantiates a nested config class (via clazz.getDeclaredConstructor().newInstance()), populates it, and calls the setter. A ReflectiveOperationException — typically a missing accessible no-arg constructor or inaccessible class — is wrapped here.","triggerScenarios":"A nested config property (e.g. <dubbo:service><dubbo:provider .../></dubbo:service> or a nested config setter) targets a class that lacks a public no-arg constructor, is an interface/abstract class, or is inaccessible. Dubbo cannot create the nested instance during refresh.","commonSituations":"A custom nested config class with only a parameterized constructor. A nested config class that is non-public or in a closed module. An interface used as a nested config type instead of a concrete class. Classpath/version mismatch where the nested class changed shape.","solutions":["Ensure the nested config class has a public no-arg constructor.","Make the nested config class public and accessible to Dubbo's classloader.","Use a concrete class, not an interface or abstract class, as the nested config type.","Verify the classpath contains the expected Dubbo version and the nested class signature."],"exampleFix":"// before\npublic class MyNestedConfig {\n    public MyNestedConfig(String arg) {} // no no-arg ctor\n}\n// after\npublic class MyNestedConfig {\n    public MyNestedConfig() {}\n    public MyNestedConfig(String arg) {}\n}","handlingStrategy":"validation","validationCode":"void assertInstantiableNested(Class<?> clazz) throws NoSuchMethodException {\n    int mods = clazz.getModifiers();\n    if (java.lang.reflect.Modifier.isAbstract(mods) || java.lang.reflect.Modifier.isInterface(mods))\n        throw new IllegalStateException(clazz + \" must be concrete\");\n    clazz.getDeclaredConstructor(); // requires public/accessible no-arg ctor\n}","typeGuard":"boolean isConcreteWithNoArgCtor(Class<?> c) {\n    int m = c.getModifiers();\n    if (java.lang.reflect.Modifier.isAbstract(m) || java.lang.reflect.Modifier.isInterface(m)) return false;\n    try { c.getDeclaredConstructor(); return true; } catch (NoSuchMethodException e) { return false; }\n}","tryCatchPattern":"try {\n    config.refresh();\n} catch (IllegalStateException e) {\n    if (e.getMessage().startsWith(\"Cannot assign nested class when refreshing config\")) {\n        // add a public no-arg ctor to the named nested class\n    }\n    throw e;\n}","preventionTips":["Give every nested config class a public no-arg constructor.","Use concrete classes (not interfaces/abstract) for nested config types.","Keep nested config classes public and on the classpath."],"tags":["config","refresh","reflection","nested-config","startup"],"backgroundTag":null,"analyzedSha":"3a3043227f5571d25eb2889de5bca22f2914843b","analyzedAt":"2026-08-14T00:43:19.853Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}