문제 정의
검증 환경
본 절은 원문 사례·문서에 등장한 버전/도구를 정리한 것이다. 별도 실험실 재현이 명시되지 않은 항목은 일반화하지 않는다.
| 항목 | 본문·원문에서 확인된 범위 |
|---|---|
| 런타임/도구 | Spring Boot 1.x |
| 런타임/도구 | Spring Boot 2.x |
| 런타임/도구 | Spring Boot 1.1.5 |
| 문서 정리일 | 2026-09-02 |
- OS/CI 세부 값은 프로젝트마다 다르므로, 적용 전 로컬에서 동일 오류 메시지를 재확인한다.
Spring Boot 애플리케이션에서 기본 Whitelabel 에러 페이지(하얀 배경의 기본 에러 화면)를 제거하기 위해, /error 경로에 사용자 컨트롤러 매핑을 직접 추가했다가 애플리케이션이 시작조차 되지 않는 상황이 발생한다.
| |
이 코드를 추가하자 컨텍스트 초기화가 실패하며 아래와 같은 예외가 발생한다.
에러 원문: Spring Boot Remove Whitelabel Error Page 출처: StackOverflow 25356781
| |
핵심 오류 메시지는 두어 가지로 요약된다.
Ambiguous mapping found— 동일한/errorURL에 매핑된 핸들러가 중복됨Cannot map 'basicErrorController' bean method— 스프링 부트가 자동 등록한BasicErrorController를 매핑할 수 없음There is already 'indexController' bean method— 이미indexController가 같은 경로를 점유한 상태
표면 증상
| 구분 | 내용 |
|---|---|
| 발생 시점 | 컨텍스트 초기화 단계 (requestMappingHandlerMapping 빈 생성) |
| 에러 유형 | BeanCreationException → IllegalStateException |
| 대상 버전 | Spring Boot 1.x 기준으로 널리 보고됨, 이후 버전에서도 같은 패턴 재현 가능 |
| 주요 메시지 | Ambiguous mapping found. Cannot map 'basicErrorController' bean method ... to {[/error]} |
| 즉시 확인 방법 | 애플리케이션 기동 로그에서 “Ambiguous mapping found” 문자열 검색 |
중요한 것은, error.whitelabel.enabled=false(또는 server.error.whitelabel.enabled=false)를 설정해도 이 에러는 계속 발생한다는 점이다. 원글 질문자도 이 설정을 추가한 뒤 “still getting the same error"라고 하였다.
이것이 표면 증상과 근본 원인이 갈라지는 핵심 지점이다. Whitelabel 페이지를 끄는 것과 /error 매핑을 사용자가 점유하는 것은 서로 별개의 문제다.
원인 탐구
왜 /error에 직접 @RestController 매핑을 추가하면 예외가 발생할까?
Spring Boot는 에러 처리를 다음 구조로 자동 구성한다.
ErrorMvcAutoConfiguration(스프링 부트 자동 구성 클래스)이basicErrorController라는 빈을 등록한다.- 이 빈은
ErrorController인터페이스의 구현체이며, 기본적으로/error경로에 매핑된다. - 결과적으로
/error는 Spring Boot가 이미 “예약"한 URL 스페이스다.
여기에 사용자가 같은 /error에 @RequestMapping을 추가하면, Spring MVC의 RequestMappingHandlerMapping은 같은 URL 조건 {[/error]}에 대해 두 개의 후보 핸들러를 발견하게 된다. 두 개 중 어느 것을 우선해야 할지 결정할 수 없으므로 Ambiguous mapping 예외를 던진다.
즉, 에러가 발생하는 시점은 원하는 “에러 페이지 제거” 가 아니라, 매핑 조건 충돌 때문이다.
| |
근본 원인 분석
근본 원인은 매우 단순하다. Spring Boot는 사용자가 ErrorController 인터페이스의 구현체를 지정하지 않으면 BasicErrorController를 자동으로 /error에 등록한다.
공식 출처(StackOverflow 채택 답변)가 명시적으로 안내한다.
Your code did not work, because Spring Boot automatically registers the
BasicErrorControlleras a Spring Bean when you have not specified an implementation ofErrorController. (코드가 동작하지 않은 이유는, 당신이ErrorController구현체를 지정하지 않았기 때문에 Spring Boot가BasicErrorController를 자동으로 스프링 빈으로 등록했기 때문이다.) — StackOverflow 25356781 채택 답변
실제 구현은 ErrorMvcAutoConfiguration.basicErrorController(Spring Boot 1.x 기준 org/springframework/boot/autoconfigure/web/ErrorMvcAutoConfiguration.java)에서 확인할 수 있다. 이 자동 구성은 조건부로 동작한다 — 사용자 정의 ErrorController 빈이 없을 때만 BasicErrorController를 만든다.
그래서 사용자가 /error에 임의의 @RequestMapping을 추가하면, 자동 등록된 BasicErrorController와 “같은 URL / 서로 다른 빈"이라는 중복 매핑 상태가 만들어져 Spring MVC가 시작에 실패한다.
원인 후보 매트릭스
| 원인 후보 | 확인 방법 | 해당 시 예상 증상 | 해결 방향 |
|---|---|---|---|
/error에 임의 컨트롤러 매핑으로 BasicErrorController와 중복 | 빈 정의 소스에서 /error 매핑 검색 | 시작 시 Ambiguous mapping ... basicErrorController | ErrorController 구현 + getErrorPath() 반환 |
whitelabel.enabled=false 만으로 해결하려 함 | application.properties/application.yml 설정 확인 | Whitelabel은 꺼지지만 /error가 여전히 점유되어 매핑 충돌 지속 | /error를 직접 매핑할 때는 ErrorController 구현 필요 |
자동 구성 전체 제외 (ErrorMvcAutoConfiguration 배제) | @SpringBootApplication(exclude=...) 또는 spring.autoconfigure.exclude 확인 | BasicErrorController가 사라져 매핑 충돌은 해결되나, 서블릿 컨테이너 기본 에러 페이지로 대체됨 | JSON/일관 응답이 목적이 아니면 보류 |
| 서버 기동 불가(= 빈 생성 실패) | 로그에서 requestMappingHandlerMapping 생성 실패 확인 | /error 충돌 외 다른 핸들러 매핑도 실패 | 근본 중복 제거 후 전체 빈 재검증 |
코드 해결책
정석 해결책은 /error를 점유할 컨트롤러가 ErrorController 인터페이스를 구현하고 getErrorPath()를 반환하게 하는 것이다. 그러면 사용자 컨트롤러가 스프링 부트의 자동 등록 BasicErrorController를 대체하게 되어 중복 매핑이 사라진다.
StackOverflow 채택 답변의 코드:
| |
개념적으로는 BasicErrorController가 수행하던 역할(에러 페이지 렌더링/응답)을 이제 IndexController가 ErrorController 구현체로서 대신 수행하게 된다. Spring Boot는 사용자 정의 ErrorController 빈이 존재하므로 자동 구성에서 BasicErrorController를 더 이상 생성하지 않는다.
JSON 응답이 필요할 때 (버전별 주의)
REST API처럼 JSON 형태의 에러 응답을 원한다면 ErrorAttributes를 주입받아 에러 정보를 반환하는 방식이 일반적이다. 단, Spring Boot 버전 1.x와 2.x는 패키지명과 시그니처가 다르다는 점을 주의해야 한다(원문의 여러 답변이 이를 지적한다).
- Spring Boot 1.x:
org.springframework.boot.autoconfigure.web.ErrorController,org.springframework.boot.autoconfigure.web.ErrorAttributes,getErrorAttributes(RequestAttributes, boolean) - Spring Boot 2.x:
org.springframework.boot.web.servlet.error.ErrorController,org.springframework.boot.web.servlet.error.ErrorAttributes,getErrorAttributes(WebRequest, ErrorAttributeOptions)
| |
잘못된 해결책
| 잘못된 접근 | 왜 권장하지 않는가 |
|---|---|
error.whitelabel.enabled=false / server.error.whitelabel.enabled=false 만 설정 | Whitelabel 페이지는 사라질 수 있으나 /error 엔드포인트 자체는 그대로 매핑되어 중복 매핑 충돌은 해결되지 않는다. 원문 질문자의 후속 코멘트가 이를 확인해준다. |
@SpringBootApplication(exclude = {ErrorMvcAutoConfiguration.class}) 또는 spring.autoconfigure.exclude로 자동 구성 전체 제외 | BasicErrorController는 사라져 충돌은 없어지지만, 예외 발생 시 서블릿 컨테이너(Tomcat 등)의 기본 에러 페이지가 대신 표시된다. 원문 답변도 “doing so will probably cause servlet container’s whitelabel pages to show up instead"라고 경고한다. |
검증 명령
해결 후 애플리케이션이 정상 기동하는지, 그리고 /error 응답이 기대대로 오는지 명령으로 확인한다.
| |
추가로, 기동 로그에서 기존의 Ambiguous mapping found 예외가 더 이상 나타나지 않는지 확인한다.
| |
향후 예방 조치
같은 에러를 다시 만나지 않기 위한 체크리스트.
/error는 스프링 부트가 예약한 경로다 — 사용자 컨트롤러로/error를 다룰 때는 반드시ErrorController인터페이스를 구현하고getErrorPath()를 반환한다.- Whitelabel 제거와
/error점유를 구분한다 —server.error.whitelabel.enabled=false는 페이지를 끄는 기능이고,/errorURL을 비우는 기능이 아니다./error를 완전히 다른 경로로 옮기려면server.error.path=/error-spring처럼 경로를 재지정하면 된다(원문 답변 참조). - 버전별 API를 확인한다 —
ErrorController/ErrorAttributes패키지와 메시지가 Spring Boot 1.x/2.x에서 다르므로, 의존성 버전을 먼저 확인한 뒤 해당 시그니처를 사용한다. - 빈 매핑 점검 — 새 컨트롤러 추가 후에는
requestMappingHandlerMapping단계에서 매핑 중복이 없는지 기동 로그로 확인한다. - 자동 구성 배제는 신중히 —
ErrorMvcAutoConfiguration전체를 배제하면 예상치 못한 서블릿 컨테이너 에러 페이지가 등장할 수 있으므로, 목적이 분명하지 않으면 피한다.
실전 적용 체크
| 환경 | 확인 사항 |
|---|---|
| 로컬 | curl로 /error 및 존재하지 않는 경로 응답 확인, 기동 로그에 Ambiguous 없음 |
| CI | 빌드 단계에서 테스트가 /error 매핑을 검증하는지 확인 (컨텍스트 로드 실패로 빌드가 깨지지 않는지) |
| 프로덕션 | 에러 응답 포맷이 클라이언트/모니터링과 일치하는지, 서블릿 컨테이너 기본 페이지로 회귀하지 않는지 확인 |
DevTrace 결론
/error를 직접 매핑할 때 발생하는 Ambiguous mapping의 핵심은 “Whitelabel 페이지를 끄는 설정"이 아니라, ErrorController 구현체를 지정하지 않아 Spring Boot가 자동 등록한 BasicErrorController가 같은 URL을 점유하고 있다는 점이다. 즉, ErrorController 인터페이스 구현 + getErrorPath() 반환으로 자동 등록 빈을 대체하면 충돌이 해결된다.
원문 출처는 문제 발견의 단서이며, 위 판단과 점검 항목은 DevTrace의 독자 분석이다.
DevTrace verdict — /error를 직접 매핑할 때 발생하는 Ambiguous mapping의 핵심은 “Whitelabel 페이지를 끄는 설정"이 아니라, ErrorController 구현체를 지정하지 않아 Spring Boot가 자동 등록한 BasicErrorController가 같은 URL을 점유하고 있다는 점이다. 즉, ErrorController 인터페이스 구현 + getErrorPath() 반환으로 자동 등록 빈을 대체하면 충돌이 해결된다.
출처:
- StackOverflow: Spring Boot Remove Whitelabel Error Page
- ErrorMvcAutoConfiguration.basicErrorController (Spring Boot 1.1.5)
참고: 위 표와 체크리스트 중 “로그 검색”, “curl 응답 상태”, “CI/프로덕션 점검” 항목은 원문 출처에 명시되지 않은 일반적인 점검 기준으로, 프로젝트 환경에 따라 일부 조정이 필요할 수 있습니다.