{"record":{"id":"cdc7d63dcbc40bb9","repo":"spring-projects/spring-security","slug":"cannot-apply-configurer-to-already-built-object","errorCode":null,"errorMessage":"Cannot apply {configurer} to already built object","messagePattern":"Cannot apply (.+?) to already built object","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"config/src/main/java/org/springframework/security/config/annotation/AbstractConfiguredSecurityBuilder.java","lineNumber":209,"sourceCode":"\t * @return the shared Objects\n\t */\n\tpublic Map<Class<?>, Object> getSharedObjects() {\n\t\treturn Collections.unmodifiableMap(this.sharedObjects);\n\t}\n\n\t/**\n\t * Adds {@link SecurityConfigurer} ensuring that it is allowed and invoking\n\t * {@link SecurityConfigurer#init(SecurityBuilder)} immediately if necessary.\n\t * @param configurer the {@link SecurityConfigurer} to add\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <C extends SecurityConfigurer<O, B>> void add(C configurer) {\n\t\tAssert.notNull(configurer, \"configurer cannot be null\");\n\t\tClass<? extends SecurityConfigurer<O, B>> clazz = (Class<? extends SecurityConfigurer<O, B>>) configurer\n\t\t\t.getClass();\n\t\tsynchronized (this.configurers) {\n\t\t\tif (this.buildState.isConfigured()) {\n\t\t\t\tthrow new IllegalStateException(\"Cannot apply \" + configurer + \" to already built object\");\n\t\t\t}\n\t\t\tList<SecurityConfigurer<O, B>> configs = null;\n\t\t\tif (this.allowConfigurersOfSameType) {\n\t\t\t\tconfigs = this.configurers.get(clazz);\n\t\t\t}\n\t\t\tconfigs = (configs != null) ? configs : new ArrayList<>(1);\n\t\t\tconfigs.add(configurer);\n\t\t\tthis.configurers.put(clazz, configs);\n\t\t\tif (this.buildState.isInitializing()) {\n\t\t\t\tthis.configurersAddedInInitializing.add(configurer);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Gets all the {@link SecurityConfigurer} instances by its class name or an empty\n\t * List if not found. Note that object hierarchies are not considered.\n\t * @param clazz the {@link SecurityConfigurer} class to look for","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/config/src/main/java/org/springframework/security/config/annotation/AbstractConfiguredSecurityBuilder.java#L191-L227","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nhttp.csrf(); http.build(); http.apply(new MyConfigurer()); // IllegalStateException\n// after\nhttp.csrf().apply(new MyConfigurer());\nSecurityFilterChain chain = http.build();","handlingStrategy":"type-guard","validationCode":"if (builder instanceof AbstractConfiguredSecurityBuilder<?,?> b && b.isBuilt()) {\n    throw new IllegalStateException(\"builder already built; create a new one\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    builder.apply(configurer);\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"already built\")) {\n        builder = createFreshBuilder();\n        builder.apply(configurer);\n    }\n}","preventionTips":["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"],"tags":["configuration","builder","illegal-state","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"}