spring-projects/spring-security · error · IllegalStateException
Cannot apply {configurer} to already built object
Error message
Cannot apply {configurer} to already built object What it means
AbstractConfiguredSecurityBuilder.add registers a SecurityConfigurer, but once the builder's buildState is 'configured' (or beyond), no new configurers may be added, so it throws IllegalStateException. This protects the invariant that configuration happens strictly before doBuild() executes the configurers.
Source
Thrown at config/src/main/java/org/springframework/security/config/annotation/AbstractConfiguredSecurityBuilder.java:209
* @return the shared Objects
*/
public Map<Class<?>, Object> getSharedObjects() {
return Collections.unmodifiableMap(this.sharedObjects);
}
/**
* Adds {@link SecurityConfigurer} ensuring that it is allowed and invoking
* {@link SecurityConfigurer#init(SecurityBuilder)} immediately if necessary.
* @param configurer the {@link SecurityConfigurer} to add
*/
@SuppressWarnings("unchecked")
private <C extends SecurityConfigurer<O, B>> void add(C configurer) {
Assert.notNull(configurer, "configurer cannot be null");
Class<? extends SecurityConfigurer<O, B>> clazz = (Class<? extends SecurityConfigurer<O, B>>) configurer
.getClass();
synchronized (this.configurers) {
if (this.buildState.isConfigured()) {
throw new IllegalStateException("Cannot apply " + configurer + " to already built object");
}
List<SecurityConfigurer<O, B>> configs = null;
if (this.allowConfigurersOfSameType) {
configs = this.configurers.get(clazz);
}
configs = (configs != null) ? configs : new ArrayList<>(1);
configs.add(configurer);
this.configurers.put(clazz, configs);
if (this.buildState.isInitializing()) {
this.configurersAddedInInitializing.add(configurer);
}
}
}
/**
* Gets all the {@link SecurityConfigurer} instances by its class name or an empty
* List if not found. Note that object hierarchies are not considered.
* @param clazz the {@link SecurityConfigurer} class to look forView on GitHub (pinned to 96852e8860)
Solutions
- Move all .apply()/.with() calls before the build() invocation in your configuration code.
- Create a fresh builder instance instead of reusing a built one; builders are single-use.
- Guard conditional configuration so it executes inside the same configuration method, before building, e.g. apply inside the SecurityFilterChain bean's lambda.
- If you need post-built access, use builder.getObject() rather than reconfiguring.
Example fix
// before http.csrf(); http.build(); http.apply(new MyConfigurer()); // IllegalStateException // after http.csrf().apply(new MyConfigurer()); SecurityFilterChain chain = http.build();
Defensive patterns
Strategy: type-guard
Validate before calling
if (builder instanceof AbstractConfiguredSecurityBuilder<?,?> b && b.isBuilt()) {
throw new IllegalStateException("builder already built; create a new one");
} Try / catch
try {
builder.apply(configurer);
} catch (IllegalStateException e) {
if (e.getMessage().contains("already built")) {
builder = createFreshBuilder();
builder.apply(configurer);
}
} Prevention
- Apply all configurers synchronously before build()
- Treat builders as single-use objects
- Never hold builders in shared/static fields
- Do conditional config inside the same configuration lambda
When it happens
Trigger: Calling .apply(configurer) or .with(...) on a builder after build() (or after configuration was finalized), e.g. adding HttpSecurity configurers after the filter chain was built, or reusing a single builder instance across two builds.
Common situations: Storing an HttpSecurity/WebSecurityCustomizer in a field and configuring it lazily after startup; calling build() twice on the same builder then applying more configurers; framework callbacks (e.g. BeanPostProcessor) touching the builder post-build.
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 already been built
- This object has not been built
- Cannot configure both a CorsConfigurationSource and a PreFli
- Headers security is enabled, but no headers will be added. E
- Invalid configuration that explicitly sets requireExplicitAu
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/cdc7d63dcbc40bb9.
Report an issue: GitHub.