{"record":{"id":"f94d179139e78da2","repo":"spring-projects/spring-framework","slug":"does-not-support-circular-references","errorCode":null,"errorMessage":" does not support circular references","messagePattern":" does not support circular references","errorType":"exception","errorClass":"FactoryBeanNotInitializedException","httpStatus":null,"severity":"error","filePath":"spring-beans/src/main/java/org/springframework/beans/factory/config/AbstractFactoryBean.java","lineNumber":164,"sourceCode":"\tpublic final T getObject() throws Exception {\n\t\tif (isSingleton()) {\n\t\t\tT instance = this.singletonInstance;\n\t\t\treturn (instance != null ? instance : getEarlySingletonInstance());\n\t\t}\n\t\telse {\n\t\t\treturn createInstance();\n\t\t}\n\t}\n\n\t/**\n\t * Determine an 'early singleton' instance, exposed in case of a\n\t * circular reference. Not called in a non-circular scenario.\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tprivate T getEarlySingletonInstance() {\n\t\tClass<?>[] ifcs = getEarlySingletonInterfaces();\n\t\tif (ifcs == null) {\n\t\t\tthrow new FactoryBeanNotInitializedException(\n\t\t\t\t\tgetClass().getName() + \" does not support circular references\");\n\t\t}\n\t\tif (this.earlySingletonInstance == null) {\n\t\t\tthis.earlySingletonInstance = (T) Proxy.newProxyInstance(\n\t\t\t\t\tthis.beanClassLoader, ifcs, new EarlySingletonInvocationHandler());\n\t\t}\n\t\treturn this.earlySingletonInstance;\n\t}\n\n\t/**\n\t * Expose the singleton instance (for access through the 'early singleton' proxy).\n\t * @return the singleton instance that this FactoryBean holds\n\t * @throws IllegalStateException if the singleton instance is not initialized\n\t */\n\tprivate T getSingletonInstance() throws IllegalStateException {\n\t\tT instance = this.singletonInstance;\n\t\tAssert.state(instance != null, \"Singleton instance not initialized yet\");\n\t\treturn instance;","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/69bf83ad716d0cfc4b0520a19b4d8b24c79d1538/spring-beans/src/main/java/org/springframework/beans/factory/config/AbstractFactoryBean.java#L146-L182","documentation":"Thrown as a FactoryBeanNotInitializedException when a singleton-scoped FactoryBean is asked for its bean before it has finished initializing AND it does not opt in to early-proxy exposure. AbstractFactoryBean.getEarlySingletonInstance calls getEarlySingletonInterfaces(); if that returns null (the default), the FactoryBean declares it cannot resolve circular references and throws. Subclasses expose early-singleton interfaces to opt in to circular-reference resolution.","triggerScenarios":"A circular bean dependency where one of the beans in the cycle is a FactoryBean that has not overridden getEarlySingletonInterfaces() to return a non-null interface array, and Spring tries to obtain an early singleton reference to it to break the cycle. getObject() is invoked during the cycle before the FactoryBean's afterPropertiesSet has populated singletonInstance.","commonSituations":"Two beans mutually referencing each other where one is an AbstractFactoryBean subclass (e.g. a custom FactoryBean<Object>); spring.main.allow-circular-references=true left on while a FactoryBean in the cycle never declared early-singleton interfaces; upgrading Spring where circular reference handling was tightened; a FactoryBean whose createInstance depends (directly/indirectly) on a bean that depends back on the FactoryBean's product.","solutions":["Break the circular dependency: inject one side lazily (@Lazy), use setter injection on one leg, or redesign so the FactoryBean does not depend on beans that depend on its product.","If early exposure is acceptable, override getEarlySingletonInterfaces() in the FactoryBean to return the interfaces that the early proxy should expose.","Disable circular references application-wide (spring.main.allow-circular-references=false) to surface such designs at startup as a deliberate error rather than a per-FactoryBean failure.","Refactor the FactoryBean to a plain @Bean method so the container handles the singleton lifecycle and circular reference resolution.","Move the cycle-breaking collaborator into an ObjectProvider<T> or Optional<T> so it is resolved on demand, not during initialization."],"exampleFix":"// before: FactoryBean in a cycle, no early-singleton interfaces\npublic class MyFactoryBean extends AbstractFactoryBean<MyType> {\n    @Override protected MyType createInstance() { return new MyType(collab); }\n    // collab depends on MyType -> cycle\n}\n\n// after: opt in to early exposure via interfaces\n@Override\nprotected Class<?>[] getEarlySingletonInterfaces() {\n    return new Class<?>[] { MyType.class };\n}","handlingStrategy":"validation","validationCode":"// Detect a FactoryBean in a cycle that cannot break early\nAbstractFactoryBean<?> fb = (AbstractFactoryBean<?>) factoryBean;\nif (inCycle && fb.getEarlySingletonInterfaces() == null) {\n    throw new IllegalStateException(fb.getClass().getName() + \" cannot participate in a circular reference\");\n}","typeGuard":"// True if the FactoryBean opts in to early circular-reference resolution\nboolean supportsCycle = ((AbstractFactoryBean<?>) fb).getEarlySingletonInterfaces() != null;","tryCatchPattern":null,"preventionTips":["Break circular dependencies using @Lazy, setter injection, or ObjectProvider.","Override getEarlySingletonInterfaces() in custom FactoryBeans that may be in cycles.","Set spring.main.allow-circular-references=false to fail fast on risky cycles.","Prefer plain @Bean methods over custom FactoryBeans for singleton lifecycle."],"tags":["spring","factory-bean","circular-dependency","lifecycle"],"backgroundTag":null,"analyzedSha":"69bf83ad716d0cfc4b0520a19b4d8b24c79d1538","analyzedAt":"2026-08-09T15:32:58.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}