/개발/Spring Boot Startup Failure: 6 Causes of UnsatisfiedDependencyException and How to Fix Them
DevelopmentSpring BootUnsatisfiedDependencyException

Spring Boot Startup Failure: 6 Causes of UnsatisfiedDependencyException and How to Fix Them

When Spring Boot will not even start because of UnsatisfiedDependencyException or No qualifying bean of type, read the stack trace backwards to pinpoint one of six causes in five minutes. Copy-paste fix code is included.

Spring Boot Startup Failure: 6 Causes of UnsatisfiedDependencyException and How to Fix Them

Spring Boot Won't Start! Diagnose 6 Causes of UnsatisfiedDependencyException in 5 Minutes

The app that started fine yesterday died this morning under 200 lines of red stack trace. Error creating bean with name ..., No qualifying bean of type ... available. A screen full of nested exception makes your stomach drop, but here's the short version: don't panic—start reading from the last line.

This post is not about runtime errors in an already-running app—JWT auth failures, Whitelabel 404s, and the like. It covers only bean registration and injection failures that prevent the application from starting at all. There are essentially only six failure patterns at this stage, and once you pinpoint the cause, most of them are a one-line fix.

How to Read a Stack Trace Backwards (Like ssh -vvv)

Read a stack trace from the top and you'll get lost. Like debugging ssh -vvv logs, you have to read from the bottom up to see the real cause. Here's a real example.

CODE
Error creating bean with name 'orderController':       ← ① 누가: orderController 생성 중
  Unsatisfied dependency expressed through constructor parameter 0;  ← ② 무엇을: 생성자 0번 파라미터 주입 실패
  nested exception is
  org.springframework.beans.factory.NoSuchBeanDefinitionException:
  No qualifying bean of type 'com.example.PaymentService' available:  ← ③ 왜: PaymentService 빈이 없음
  expected at least 1 bean which qualifies as autowire candidate

Pull out just these three elements and you're done.

  1. Who (the bean that failed to create): orderController
  2. What (what it tried to inject): constructor parameter 0
  3. Why (root cause): NoSuchBeanDefinitionException → no PaymentService bean in the container

The exception type on the last line tells you which way to look.

Last-line exception messageMeaningLikely cause
NoSuchBeanDefinition: No qualifying bean ... expected at least 10 beansMissing component / outside scan range / conditional bean not created
NoUniqueBeanDefinitionException: expected single matching bean but found 22+ beansMultiple registrations of the same type; need @Qualifier
Requested bean is currently in creation / circular referenceMutual referencesConstructor circular reference

Diagnosis Table for 6 Causes + Copy-Paste Fixes

Here's the mapping table at a glance.

#Error clueCauseFix
1No qualifying bean ... expected at least 1Missing @Component or outside scan rangeAdd the annotation / @ComponentScan(basePackages=...)
2expected single matching bean but found 2Multiple implementations@Qualifier / @Primary
3currently in creationConstructor circular referenceSplit responsibilities / @Lazy
4Bean missing entirely@ConditionalOnProperty / @Profile not metEnable the property/profile
5NoUniqueBeanDefinitionExceptionTwo beans of the same type@Primary or explicit injection
6Fails only in testsBean missing from the slice context@MockBean / adjust slice scope

Cause 1. Missing component or outside scan range

This is the most common one. @SpringBootApplication only scans its own package and subpackages. If a bean lives under a separate root like com.example.common, it won't be picked up.

JAVA
@SpringBootApplication
@ComponentScan(basePackages = {"com.example.app", "com.example.common"})
public class Application { }

And plenty of people just forget @Service/@Component on the class itself—check that first.

Causes 2 & 5. Multiple implementations → @Qualifier / @Primary

If PaymentService has two implementations, KakaoPayService and NaverPayService, Spring has no idea which one to inject and throws NoUniqueBeanDefinitionException.

JAVA
@Service @Qualifier("kakaoPay")
public class KakaoPayService implements PaymentService { }

@Service @Primary  // 기본 후보 지정
public class NaverPayService implements PaymentService { }

// 주입 시 명시 선택
public OrderController(@Qualifier("kakaoPay") PaymentService paymentService) { ... }

Cause 3. Constructor circular reference → @Lazy

If A injects B via constructor and B injects A, that's a circular reference. From Spring Boot 2.6+ the default of spring.main.allow-circular-references is false, so startup fails immediately (problems that used to hide behind field injection now surface early thanks to constructor injection being the recommended style). The right fix is to split responsibilities, but when you need it now:

JAVA
public AService(@Lazy BService bService) {
    this.bService = bService;
}

Cause 4. Conditional bean never created

If the @ConditionalOnProperty condition isn't met, the bean is never created at all.

JAVA
@Bean
@ConditionalOnProperty(name = "feature.pay.enabled", havingValue = "true")
public PaymentService paymentService() { ... }

→ You need feature.pay.enabled: true in application.yml for the bean to appear. Same story with @Profile("prod").

Cause 6. Fails only in tests

@WebMvcTest loads only the controller slice, so service beans aren't there. Fill in the dependencies with @MockBean.

JAVA
@WebMvcTest(OrderController.class)
class OrderControllerTest {
    @MockBean PaymentService paymentService;
    @Autowired MockMvc mockMvc;
}

A note from the field

The first thing I do after scaffolding a new project is collapse the package structure under a single com.example.app root. Cause 1—forgetting basePackages with multi-root packages—accounts for more than half of all bean-injection issues I see. And when an auto-config bean doesn't appear, it's faster to suspect a missing dependency in build.gradle than to start reading library source.

Common Pitfalls & Verification Routine

  • Multi-module: If beans from the core module aren't picked up in the api module, check that the dependency is there and that the package is included in the scan path (@ComponentScan).
  • Auto-config bean missing because of a missing dependency: Without the library, @ConditionalOnClass auto-configuration is disabled entirely.
GROOVY
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
  • The trap of @Autowired(required=false) / Optional workarounds: The error disappears, but you get an NPE later at runtime. It's only a workaround that hides the root cause.
  • Check actually registered beans with Actuator: Look instead of guessing.
PROPERTIES
management.endpoints.web.exposure.include=beans

Hit /actuator/beans and check whether the bean name is in the list—you'll immediately know whether it wasn't scanned or wasn't created because of a condition. Note that Spring Boot 3.x switched to the Jakarta namespace (jakarta.*), so javax.*-based libraries can be dropped from bean scanning/auto-config. With GraalVM Native Image, reflection-based bean registration can be missing at build time and needs extra hints.

Conclusion: One-Page Diagnosis Checklist

  1. Read the stack trace from the bottom and check the exception type
  2. No qualifying bean → missing component / scan range / conditional bean
  3. expected single ... found 2@Qualifier / @Primary
  4. currently in creation → circular reference; split design or @Lazy
  5. Fails only in tests → slice scope + @MockBean
  6. When in doubt, check /actuator/beans for actual registration

Those "200 red lines" are really just bodyguards for the last line. Make reading backwards a habit, and get into the routine of checking the bean list with Actuator ahead of time—startup failures stop being scary.

FAQ

Q. I added @Component but still get No qualifying bean. A. It's outside the scan range almost 100% of the time. If that class's package is not a subpackage of where @SpringBootApplication lives, spell it out in @ComponentScan(basePackages=...).

Q. @Repository is picked up but my class isn't. A. That's a signal that the Repository is inside auto-config/scan range and only your class is outside. Check both the package location and whether the annotation is actually on the class.

Q. Bean injection fails only in tests. A. Slices like @WebMvcTest and @DataJpaTest load only a subset of beans. Fill required dependencies with @MockBean, or use @SpringBootTest if you need the full context.

Q. How do I know it's a circular reference? A. If the message contains currently in creation or circular reference, that's definitive. Spring Boot 2.6+ blocks it by default, so it shows up immediately at startup.

Q. With two implementations, can I just always use @Primary? A. @Primary is appropriate only when there is clearly one default implementation. If you need to choose per use site, it's safer and more explicit to use @Qualifier at each injection point.

확인 정보
✦ ✦ ✦
편집 검토 · Editorial Review

Nodelog는 모든 콘텐츠의 내용과 출처를 공개 전에 검토합니다. 환경(OS·버전)에 따라 결과가 달라질 수 있는 기술 정보는 공식 문서와 함께 확인하며, 검토 기준과 정정 원칙은 편집 정책에서 안내합니다. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.

편집 책임 · Nodelog 기술 편집팀·발행 · ·업데이트 ·

Comments

Be the first to comment.