{"record":{"id":"b1108e9096bf69bb","repo":"spring-projects/spring-security","slug":"this-object-has-already-been-built","errorCode":null,"errorMessage":"This object has already been built","messagePattern":"This object has already been built","errorType":"exception","errorClass":"AlreadyBuiltException","httpStatus":null,"severity":"error","filePath":"config/src/main/java/org/springframework/security/config/annotation/AbstractSecurityBuilder.java","lineNumber":41,"sourceCode":" * time.\n *\n * @param <O> the type of Object that is being built\n * @author Rob Winch\n *\n */\npublic abstract class AbstractSecurityBuilder<O> implements SecurityBuilder<O> {\n\n\tprivate AtomicBoolean building = new AtomicBoolean();\n\n\tprivate O object;\n\n\t@Override\n\tpublic final O build() {\n\t\tif (this.building.compareAndSet(false, true)) {\n\t\t\tthis.object = doBuild();\n\t\t\treturn this.object;\n\t\t}\n\t\tthrow new AlreadyBuiltException(\"This object has already been built\");\n\t}\n\n\t/**\n\t * Gets the object that was built. If it has not been built yet an Exception is\n\t * thrown.\n\t * @return the Object that was built\n\t */\n\tpublic final O getObject() {\n\t\tif (!this.building.get()) {\n\t\t\tthrow new IllegalStateException(\"This object has not been built\");\n\t\t}\n\t\treturn this.object;\n\t}\n\n\t/**\n\t * Subclasses should implement this to perform the build.\n\t * @return the object that should be returned by {@link SecurityBuilder#build()}.\n\t * @throws Exception if an error occurs","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/config/src/main/java/org/springframework/security/config/annotation/AbstractSecurityBuilder.java#L23-L59","documentation":"AbstractSecurityBuilder.build() uses an AtomicBoolean 'building' flag with compareAndSet so the object can only be built once; a second build() call throws AlreadyBuiltException('This object has already been built'). Builders are deliberately single-use to guarantee a consistent, immutable built object.","triggerScenarios":"Invoking build() a second time on the same builder (e.g. AuthenticationManagerBuilder, HttpSecurity, ProviderManager builders), typically by calling build() manually and then letting the framework build again, or building in a loop/refresh without recreating the builder.","commonSituations":"Calling securityContextBuilder.build() inside @PostConstruct and again from another bean; Spring context refresh re-invoking configuration on a cached builder; tests reusing a static builder across test cases.","solutions":["Call build() only once per builder instance; create a new builder for each build cycle.","Use getObject() to retrieve the already-built object instead of building again.","Store the built result yourself (e.g. in a field) and reuse it rather than re-triggering build().","In tests, construct builders in setup (@BeforeEach) so each test gets a fresh instance."],"exampleFix":"// before\nmanager = builder.build();\n// later, same builder\nother = builder.build(); // AlreadyBuiltException\n// after\nmanager = builder.build();\nother = manager; // reuse built object, or new SomeBuilder() for a fresh build","handlingStrategy":"type-guard","validationCode":"if (builder instanceof AbstractSecurityBuilder<?> b && b.getObject() != null) {\n    // already built; do not call build() again\n}","typeGuard":null,"tryCatchPattern":"try {\n    object = builder.build();\n} catch (AlreadyBuiltException e) {\n    object = builder.getObject(); // reuse previously built instance\n}","preventionTips":["Call build() exactly once per builder","Cache the built object instead of rebuilding","Use fresh builders per context refresh or test","Prefer framework-managed bean exposure over manual build()"],"tags":["builder","illegal-state","lifecycle","spring-security"],"backgroundTag":"invalid-state-transition","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}