{"record":{"id":"de23b81adbb6348e","repo":"quarkusio/quarkus","slug":"multiple-inject-constructors-on-theclass","errorCode":null,"errorMessage":"Multiple @Inject constructors on ${theClass}","messagePattern":"Multiple @Inject constructors on (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java","lineNumber":1788,"sourceCode":"    final class NewRecorder extends DeferredArrayStoreParameter {\n        final Class<?> theClass;\n        final Constructor<?> injectCtor;\n        final List<DeferredParameter> deferredParameters = new ArrayList<>();\n\n        NewRecorder(Class<?> theClass) {\n            super(theClass.getName());\n            this.theClass = theClass;\n            Constructor<?> injectCtor = null;\n            Constructor<?>[] ctors = theClass.getDeclaredConstructors();\n            if (ctors.length == 1) {\n                injectCtor = ctors[0];\n            } else {\n                for (var i : ctors) {\n                    if (i.isAnnotationPresent(Inject.class)) {\n                        if (injectCtor == null) {\n                            injectCtor = i;\n                        } else {\n                            throw new RuntimeException(\"Multiple @Inject constructors on \" + theClass);\n                        }\n                    }\n                }\n                if (injectCtor == null) {\n                    throw new RuntimeException(\n                            \"Could not determine constructor for \" + theClass + \" add @Inject to a constructor\");\n                }\n            }\n            this.injectCtor = injectCtor;\n        }\n\n        void preWrite(Map<Object, DeferredParameter> parameterMap) {\n            if (injectCtor != null) {\n                try {\n                    java.lang.reflect.Type[] parameterTypes = injectCtor.getGenericParameterTypes();\n                    Annotation[][] parameterAnnotations = injectCtor.getParameterAnnotations();\n                    for (int i = 0; i < parameterTypes.length; i++) {\n                        java.lang.reflect.Type param = parameterTypes[i];","sourceCodeStart":1770,"sourceCodeEnd":1806,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java#L1770-L1806","documentation":"When recording a class instantiation, the recorder uses the @Inject-annotated constructor if one exists. CDI rules allow at most one @Inject constructor; finding two makes constructor selection ambiguous, so Quarkus fails the build. This almost always indicates a violation of CDI semantics in the class being recorded.","triggerScenarios":"Passing to a @Record method a class that declares two constructors annotated with @Inject (invalid CDI); a merge/refactor that duplicated the annotation on an additional constructor.","commonSituations":"Classes evolved by multiple contributors each annotating their preferred constructor; code-generator output that stamps @Inject on every constructor.","solutions":["Keep @Inject on exactly one constructor and remove it from the others","If multiple construction paths are needed, keep one @Inject constructor and provide other constructors without the annotation","Annotate only the canonical constructor (e.g. the record's canonical constructor) used for injection"],"exampleFix":"// before\n@Inject public Foo(A a) {...}\n@Inject public Foo(A a, B b) {...}\n// after\n@Inject public Foo(A a, B b) {...}\npublic Foo(A a) { this(a, null); }","handlingStrategy":"validation","validationCode":"long injectCtors = Arrays.stream(clazz.getConstructors())\n    .filter(c -> c.isAnnotationPresent(Inject.class)).count();\nif (injectCtors > 1) {\n    throw new IllegalStateException(clazz + \" has \" + injectCtors + \" @Inject constructors\");\n}","typeGuard":"boolean singleInjectCtor(Class<?> c) {\n    return Arrays.stream(c.getConstructors())\n        .filter(k -> k.isAnnotationPresent(Inject.class)).count() <= 1;\n}","tryCatchPattern":"try {\n    recorder.record(value);\n} catch (RuntimeException e) {\n    if (String.valueOf(e.getMessage()).startsWith(\"Multiple @Inject constructors\")) {\n        throw new IllegalStateException(\"Keep @Inject on exactly one constructor of \" + value.getClass(), e);\n    }\n    throw e;\n}","preventionTips":["Follow CDI rule: at most one @Inject constructor per class","Audit generated/refactored code for duplicated @Inject annotations","Prefer a single canonical constructor and delegate via this(...)"],"tags":["quarkus","cdi","constructor"],"backgroundTag":"multiple-inject-constructors","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"}