{"record":{"id":"e2cd0a864490b074","repo":"apache/maven","slug":"circular-references","errorCode":null,"errorMessage":"Circular references: {}","messagePattern":"Circular references: (.+?)","errorType":"exception","errorClass":"DIException","httpStatus":null,"severity":"error","filePath":"impl/maven-di/src/main/java/org/apache/maven/di/impl/InjectorImpl.java","lineNumber":171,"sourceCode":"        Key<?> key = Key.of(clazz, ReflectionUtils.qualifierOf(clazz));\n        if (clazz.isInterface()) {\n            bindings.computeIfAbsent(key, $ -> new HashSet<>());\n            if (key.getQualifier() != null) {\n                bindings.computeIfAbsent(Key.ofType(clazz), $ -> new HashSet<>());\n            }\n        } else if (!Modifier.isAbstract(clazz.getModifiers())) {\n            Binding<?> binding = ReflectionUtils.generateImplicitBinding(key);\n            doBind(key, binding);\n        }\n        return this;\n    }\n\n    private final LinkedHashSet<Key<?>> current = new LinkedHashSet<>();\n\n    private Injector doBind(Key<?> key, Binding<?> binding) {\n        if (!current.add(key)) {\n            current.add(key);\n            throw new DIException(\"Circular references: \" + current);\n        }\n        try {\n            doBindImplicit(key, binding);\n            Class<?> cls = key.getRawType().getSuperclass();\n            while (cls != Object.class && cls != null) {\n                doBindImplicit(Key.of(cls, key.getQualifier()), binding);\n                if (key.getQualifier() != null) {\n                    bind(Key.ofType(cls), binding);\n                }\n                cls = cls.getSuperclass();\n            }\n            return this;\n        } finally {\n            current.remove(key);\n        }\n    }\n\n    protected <U> Injector bind(Key<U> key, Binding<U> b) {","sourceCodeStart":153,"sourceCodeEnd":189,"githubUrl":"https://github.com/apache/maven/blob/e4093d4e120eac99d6bdce5ba67cace2f3085c97/impl/maven-di/src/main/java/org/apache/maven/di/impl/InjectorImpl.java#L153-L189","documentation":"InjectorImpl.doBind keeps a LinkedHashSet ('current') as a stack of keys currently being registered. If binding a key re-enters doBind for a key already on that stack, it throws DIException 'Circular references:' followed by the full key path, where the repeated key marks the cycle. This guards the registration phase; instance-resolution cycles are reported separately by the resolution stack check.","triggerScenarios":"Calling bind/bindInstance/bindSupplier/bindImplicit for key K while K's own binding is still in progress — e.g. binding hooks, implicit-binding generation, or qualifier-aware superclass registration that re-binds the same key re-entrantly.","commonSituations":"Extension code that performs injector configuration from inside binding callbacks; repeated bootstrap of the same module against one injector; custom Scope or Binding implementations with side effects during registration.","solutions":["Read the key path in the message: the key that appears twice delimits the cycle; remove one of the two registration sites","Move all bind* calls to top-level bootstrap code instead of performing them during binding callbacks","If two modules must contribute bindings for the same key, let them register normally so the binding set handles precedence rather than re-entering doBind","If no user code re-binds keys, report the framework-internal re-entrancy to maven-di"],"exampleFix":"// before: binding A re-enters binding A during registration\ninjector.bindInstance(A.class, makeA(injector)); // makeA() binds A.class again\n\n// after: finish construction first, then register once\nA a = makeA();\ninjector.bindInstance(A.class, a);","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    injector.bindInstance(A.class, a);\n} catch (DIException e) {\n    if (e.getMessage().startsWith(\"Circular references\")) {\n        // message lists the key cycle: remove one of the re-entrant bind sites\n        throw new ConfigurationException(\"re-entrant binding detected: \" + e.getMessage(), e);\n    }\n    throw e;\n}","preventionTips":["Never call injector bind methods from inside binding suppliers, initializers, or callbacks","Register each key once at top-level bootstrap and avoid re-entrant configuration"],"tags":["di","circular-dependency","binding","maven"],"backgroundTag":"circular-dependency-injection","analyzedSha":"e4093d4e120eac99d6bdce5ba67cace2f3085c97","analyzedAt":"2026-08-21T22:58:24.034Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}