A bean you expected from auto-configuration isn't in the context. How do you use the condition report to find out why, and what are the usual causes?
answer
- --debug → find class in Negative matches
- OnClass = missing dependency
- OnMissingBean = you already defined it
- OnProperty = flag unset/wrong value
- OnMissingBean ordering-sensitive → duplicate beans
basics
~20 sRun with --debug and find the auto-config under Negative matches; the reason line names the failing condition. Usual causes: a required class is missing from the classpath (@ConditionalOnClass), a property isn't set (@ConditionalOnProperty), or your own bean already exists so auto-config backed off (@ConditionalOnMissingBean).
solid answer
~40 sEnable --debug and search the CONDITIONS EVALUATION REPORT for the auto-config class. Under Negative matches the report states the exact condition that failed. The common culprits: (1) @ConditionalOnClass — the starter/dependency isn't on the classpath, so add it; (2) @ConditionalOnProperty — a gating property is unset or matches the wrong value; (3) @ConditionalOnMissingBean — you (or another config) already defined a bean of that type, so auto-config deliberately backed off; (4) @ConditionalOnBean — a prerequisite bean doesn't exist yet; (5) the class is under Exclusions. A subtle one: @ConditionalOnMissingBean is evaluated in configuration-processing order, so a user bean defined 'after' the auto-config may not be seen, causing a duplicate. If the config is a Positive match but the bean's still absent, check the @Bean-method-level conditions and active profiles.
code
java · 22 lines// Symptom: no RedisTemplate bean. Report shows:
//
// Negative matches:
// RedisAutoConfiguration:
// Did not match:
// - @ConditionalOnClass did not find required class
// 'org.springframework.data.redis.core.RedisOperations' (OnClassCondition)
//
// Cause + fix: the Redis starter is missing.
// implementation("org.springframework.boot:spring-boot-starter-data-redis")
// Symptom: your custom ObjectMapper is ignored / duplicated.
// Define the override in a plain @Configuration so it's seen early:
@Configuration(proxyBeanMethods = false)
class JacksonOverrideConfig {
@Bean
ObjectMapper objectMapper() { // seen before JacksonAutoConfiguration
return new ObjectMapper().findAndRegisterModules();
}
}
// Now JacksonAutoConfiguration#jacksonObjectMapper appears under
// Negative matches: @ConditionalOnMissingBean found beans 'objectMapper'.go deeper
Enable --debug, find the class in Negative matches, read the reason. Know OnClass = missing dependency.
Enumerate the common failing conditions and their concrete fixes.
Explain the OnMissingBean ordering gotcha and Positive-but-still-missing (nested @Bean conditions).
Connect to auto-config ordering (@AutoConfigureBefore/After), bean-override policy, and correct override placement patterns.
## Systematic procedure 1. **Reproduce** with `--debug` (or hit `/actuator/conditions`). 2. **Locate** the auto-config by name (e.g. `RedisAutoConfiguration`, `DataSourceAutoConfiguration`). 3. **Classify** where it appears: - **Negative matches** → read the failing condition (the fix is right there). - **Exclusions** → it was excluded on purpose (`spring.autoconfigure.exclude` / `exclude=`). Remove the exclusion. - **Positive matches** but bean still missing → the class ran; inspect nested `@Bean` conditions, profiles, and property values. - **Absent entirely** → the auto-config isn't registered at all (wrong/missing starter, or not listed in `META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports`). ## The usual failing conditions and their fixes - **`@ConditionalOnClass did not find required class '...'`** → the dependency/starter is missing. Add it. This is the single most common cause. - **`@ConditionalOnMissingBean ... found beans '...'`** → auto-config's whole point is 'give you one only if you didn't'. You already declared that bean type, so it stepped aside. If you wanted the auto one, remove/rename yours; if you wanted yours, this is working as intended. - **`@ConditionalOnProperty (x.y) did not find property'** or matched wrong value** → set/correct the property. Watch `havingValue` and `matchIfMissing`. - **`@ConditionalOnBean` did not find bean** → an upstream bean this one depends on wasn't created (often a chain — fix the root cause first). - **`@ConditionalOnMissingClass found unwanted class`** → something on the classpath vetoes it (e.g. presence of an alternative implementation). - **`@ConditionalOnWebApplication` / `@ConditionalOnNotWebApplication`** → wrong application type (servlet vs reactive vs none). ## The ordering gotcha (senior insight) `@ConditionalOnMissingBean` only sees beans that have been **registered so far** when the condition is evaluated. Auto-configs are ordered (via `@AutoConfiguration(before/after)` / `@AutoConfigureBefore`/`@AutoConfigureAfter`), and user `@Configuration` is generally processed before auto-config. But if your bean is contributed by a component scanned/registered *after* the auto-config's condition runs, the condition may not see it → you get **two** beans or an unexpected auto bean. The lesson: define overriding beans in a plain user `@Configuration` (processed early), not somewhere that races the auto-config. This ordering subtlety is exactly what the report helps you catch: you'll see the auto-config as a Positive match ('did not find any beans') even though your bean also exists. ## Reading the message text Messages originate from `ConditionOutcome.getMessage()` produced by conditions like `OnClassCondition`, `OnBeanCondition`, `OnPropertyCondition`. They're descriptive and stable enough to act on, though not a formal contract to parse in code. ## Related: bean overriding Even if a bean exists, `spring.main.allow-bean-definition-overriding` (default false since Boot 2.1) affects duplicate-definition behavior — a duplicate now throws rather than silently overriding. That's a different failure mode but often co-occurs with condition confusion. ## Summary heuristic 'Expected bean missing' → Negative match → 90% of the time it's OnClass (missing dep), OnProperty (unset flag), or OnMissingBean (you defined it). The report tells you which in one line.
- Why might you end up with two beans of a type even though the auto-config uses @ConditionalOnMissingBean?Because @ConditionalOnMissingBean only sees beans registered before it is evaluated. If your bean is contributed after the auto-config's condition runs (bad ordering), the condition finds nothing and creates its own — you get two. Define overrides in early-processed user @Configuration.
- The report shows the auto-config under Positive matches but the bean still isn't there. What now?The class ran, so the class-level conditions passed. Check the individual @Bean method conditions (a nested @ConditionalOnProperty/OnMissingBean can veto just that bean), active profiles, and the actual property values feeding it.
saying these in an interview costs you the question
- Assuming a missing bean always means a missing dependency (could be OnMissingBean backing off because you defined it)
- Not knowing @ConditionalOnMissingBean is ordering-sensitive
- Trying to 'force' the bean by excluding random auto-configs instead of reading the reason line