spring-projects/spring-security · error · AlreadyBuiltException
This object has already been built
Error message
This object has already been built
What it means
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.
Source
Thrown at config/src/main/java/org/springframework/security/config/annotation/AbstractSecurityBuilder.java:41
* time.
*
* @param <O> the type of Object that is being built
* @author Rob Winch
*
*/
public abstract class AbstractSecurityBuilder<O> implements SecurityBuilder<O> {
private AtomicBoolean building = new AtomicBoolean();
private O object;
@Override
public final O build() {
if (this.building.compareAndSet(false, true)) {
this.object = doBuild();
return this.object;
}
throw new AlreadyBuiltException("This object has already been built");
}
/**
* Gets the object that was built. If it has not been built yet an Exception is
* thrown.
* @return the Object that was built
*/
public final O getObject() {
if (!this.building.get()) {
throw new IllegalStateException("This object has not been built");
}
return this.object;
}
/**
* Subclasses should implement this to perform the build.
* @return the object that should be returned by {@link SecurityBuilder#build()}.
* @throws Exception if an error occursView on GitHub (pinned to 96852e8860)
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.
Example fix
// before manager = builder.build(); // later, same builder other = builder.build(); // AlreadyBuiltException // after manager = builder.build(); other = manager; // reuse built object, or new SomeBuilder() for a fresh build
Defensive patterns
Strategy: type-guard
Validate before calling
if (builder instanceof AbstractSecurityBuilder<?> b && b.getObject() != null) {
// already built; do not call build() again
} Try / catch
try {
object = builder.build();
} catch (AlreadyBuiltException e) {
object = builder.getObject(); // reuse previously built instance
} Prevention
- 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()
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- This object has not been built
- Cannot apply {configurer} to already built object
- This has already been built with the following stacktrace. {
- Cannot configure both a CorsConfigurationSource and a PreFli
- Headers security is enabled, but no headers will be added. E
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/b1108e9096bf69bb.
Report an issue: GitHub.