{"record":{"id":"f887b7cc4c93c60d","repo":"gradle/gradle","slug":"s-is-a-non-static-inner-class","errorCode":null,"errorMessage":"%s is a non-static inner class.","messagePattern":"(.+?) is a non-static inner class\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"platforms/core-configuration/model-core/src/main/java/org/gradle/internal/instantiation/generator/Jsr330ConstructorSelector.java","lineNumber":71,"sourceCode":"        CachedConstructor constructor = constructorCache.get(type, () -> {\n            try {\n                validateType(type);\n                ClassGenerator.GeneratedClass<?> implClass = classGenerator.generate(type);\n                ClassGenerator.GeneratedConstructor<?> generatedConstructor = InjectUtil.selectConstructor(implClass, type);\n                return CachedConstructor.of(generatedConstructor);\n            } catch (RuntimeException e) {\n                return CachedConstructor.of(e);\n            }\n        });\n        return Cast.uncheckedCast(constructor.getConstructor());\n    }\n\n    private static <T> void validateType(Class<T> type) {\n        if (!type.isInterface() && type.getEnclosingClass() != null && !Modifier.isStatic(type.getModifiers())) {\n            TreeFormatter formatter = new TreeFormatter();\n            formatter.node(type);\n            formatter.append(\" is a non-static inner class.\");\n            throw new IllegalArgumentException(formatter.toString());\n        }\n    }\n\n    public static class CachedConstructor {\n        private final ClassGenerator.GeneratedConstructor<?> constructor;\n        private final RuntimeException error;\n\n        private CachedConstructor(ClassGenerator.GeneratedConstructor<?> constructor, RuntimeException error) {\n            this.constructor = constructor;\n            this.error = error;\n        }\n\n        public ClassGenerator.GeneratedConstructor<?> getConstructor() {\n            if (error != null) {\n                throw error;\n            }\n            return constructor;\n        }","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/gradle/gradle/blob/534f27719b66953f95cc907aae7f2c1b12f5482d/platforms/core-configuration/model-core/src/main/java/org/gradle/internal/instantiation/generator/Jsr330ConstructorSelector.java#L53-L89","documentation":"Jsr330ConstructorSelector.validateType rejects non-static inner classes before any constructor selection runs: the generated decorator subclass cannot synthesize the implicit reference to an enclosing instance that a non-static inner class requires, so instantiation would be impossible. Interfaces, top-level classes, and static nested classes pass.","triggerScenarios":"Passing Class<Helper> where Helper is a nested class without the static modifier to a JSR-330-based instantiator; validation runs once per type inside the constructor cache and the failure is replayed for every later attempt.","commonSituations":"Helper classes nested inside plugin classes for packaging convenience; top-level classes moved into nested positions without adding static; note that Kotlin nested classes are fine unless marked inner.","solutions":["Declare the nested class static: public static class Helper.","Move the class to top level.","Model the type as an interface, which passes this check automatically."],"exampleFix":"// before\nclass Outer {\n    class Helper {} // carries implicit Outer.this\n}\n// after\nclass Outer {\n    static class Helper {}\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"static boolean isInjectable(Class<?> type) {\n    return type.isInterface()\n        || type.getEnclosingClass() == null\n        || Modifier.isStatic(type.getModifiers());\n}","tryCatchPattern":null,"preventionTips":["Default nested helper classes to static.","Add a build-time scan over the types handed to the instantiator to catch non-static nested classes early."],"tags":["gradle","dependency-injection","inner-class","class-structure"],"backgroundTag":"non-static-inner-class-injection","analyzedSha":"534f27719b66953f95cc907aae7f2c1b12f5482d","analyzedAt":"2026-08-22T08:09:12.375Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}