| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 |
- 윤성우 열혈자료구조
- Stack
- 메모리구조
- Graph
- stream
- 이스케이프 문자
- C programming
- 윤성우의 열혈 자료구조
- coding test
- 알기쉬운 알고리즘
- Selection Sorting
- s
- buffer
- list 컬렉션
- R
- datastructure
- 이것이 자바다
- JSON
- 혼자 공부하는 C언어
- Algorithm
- Serialization
- C 언어 코딩 도장
- insertion sort
- Today
- Total
Engineering Note
[Error Handling] 에러 메시지의 구조, 그리고 ‘Caused by’ 본문
[Error Handling] 에러 메시지의 구조, 그리고 ‘Caused by’
Software Engineer Kim 2025. 7. 10. 19:10스프링 부트 테스트를 하다가 에러가 발생했다. 에러 술이 무려 수십줄이었다. 평소에 에러를 잘 해결한다고 생각했지만, 막상 긴 에러를 만나면, 당혹스럽긴하다. 그래서 이번기회에 에러메세지를 잘 읽는 법과 에러메세지 구조에 대해 한 번 정리하려고 한다.
아무리 복잡한 에러도 간단한 에러구조에서 확장된 형태일 뿐 간단한 에러에 대해 이해하면 긴 에러라도 어떤 스택트레이스로 발생한지 파악할 수 있다.
1. 간단한 스택트레이스 에러메시지
package exception.cause;
public class SingleCauseExample {
public static void main(String[] args) {
methodA();
}
static void methodA() {
throw new NullPointerException("NPE 발생!");
}
}
exception 패키지에 cuase 패키지 아래애 SingleCauseExample의 main 메서드에서 같은 패키지의 static 메서드인 methodA를 호출하다가 에러가 발생하는 코드다.
에러 메세지는 아래처럼 찍힌다.

첫 줄은 발생한 에러 클래스명과 어떤 스레드 인지 말해준다. 그리고 ':' 콜론 옆에는 Exception 클래스에서 전달한 메세지 스트링이 찍힌다. 간단히 보면, NullPointException이 발생했다는 걸 알 수 있게 해주는 에러메세지다.
그 다음 줄을 보면 at과 함께 exception.cause패키지의 SingleCauseExample 클래스의 methodA 소스코드 위치는 9번라인이라고 친절히 설명하고 있다.
여기서 Java를 배울 때 배웠던, '클래스명은 대문자로 작성한다'라는 규칙이 중요한데, 우리가 작성한 코드면 에러메세지를 파악하기 편하겠지만, 다른 사람이 작성한 라이브러리 등을 가져와서 사용할 경우 대문자를 기준으로 앞의 글자는 패키지고, 대문자가 에러가 발생한 클래스라는걸 알 수 있다.
그리고 이 SingleCuaseExample의 methodA는 exception.cause(같은 패키지)의 SingleCauseExample 클래스의 main에서 호출했다는 걸 알수 있다.
진짜 에러가 발생한 지검은 at이 처음 나오는 지점이고 그 아래는 스택트레이스에 따라 메서드 스택을 보여주는 구조다.
2.
package exception.cause;
public class StackTraceFiveLevels {
public static void main(String[] args) {
method1();
}
static void method1() { method2();}
static void method2() { method3();}
static void method3() { method4();}
static void method4() { method5();}
static void method5() {throw new RuntimeException();}
}
아까 보다는 조금 더 복잡한 호출 구조를 가지고 있는 경우다. main 메서드에서 method1을 호출하고, 그다음 method2 -> method3 -> method4 -> method5를 호출하는데 method5에서 RuntimeException이 발생한다.
에러메세지를 분석해보면 예측한대로 RuntimeException이 발생했다고 알려주고 있고, 그 다음 첫 줄이 실제 그 예외가 발생한 클래스와 메서드의 위치를 알려주고 있다. 그 다음 부터는 예외 발생한 메서드를 호출한 구조를 보여준다.

에러를 직접 발생시켜보면서 알 수 있듯이 에러메세지는 첫 줄과 마지막 줄이 중요하다. 첫 줄은 어떤 에외 인지와 스택트레이스의 가장 위인 실제 에러가 발생한 지점을 알려준는 정보이기 때문이다. 그리고 마지막 줄은 호출한 경로를 알려주기 때문이다. 비즈니스 로직상 실제 호출한 지점 자체 전후에서 값을 전달을 잘못해서 에러가 발생한 경우가 많기 때문이다.
그런데 이렇게 at만 찍히는 경우가 아니라 Caused By로 찍히는 에러메세지도 있는데 이건 어떤 경우에 표시되는 에러메시지 인지 알아보자.
3.
package exception.cause;
public class SingleCauseExample {
public static void main(String[] args) {
try {
methodA();
} catch (Exception e){
throw new RuntimeException(e);
}
}
static void methodA() {
throw new NullPointerException("NPE 발생!");
}
}
첫 번째 예시와 유사하지만, 다른점은 에러가 발생이 예상되는 지점에서 try catch로 감싸고 RuntimeException 예외를 던졌다. 그랬을 때 에러메세지를 살펴보자.
가장 첫 줄은 Exception이라는 키워드와 함께 main 스레드에서 발생했다는 걸 알 수 있고, 발생 에러는 RuntimeException인데, ':' 우측에 NullPointerException이라고 쓰여있다. 실제 발생한 에러를 나타내는 에러메세지다. 그리고 다음줄에 at으로 이 RuntimeException이 발생한 지점은 exception.cause 패키지의 SingleCauseExample 클래스의 8라인의 메인 메서드이다.
그리고 원인을 나타내는 Caused by 키워드가 있고, 실제 발생 에러인 NullPointerException이 쓰여있다. 그리고 다시 여기에 대한 스택트레이스가 쓰여있는데, Caused by 처음에 나오는 at은 Caused by 에 대항하는 NullPointerException이 발생한 위치이고, 그 다음 at은 methodA를 호출한 main 메서드의 위치가 패키지 구조와 함께 쓰여있다.

여기서 알 수 있는건, 항상 에러메세지를 얘기할 때 Caused By가 가장 핵심 원인이니 여기를 보라고 하는 이유를 알 수 있다. Caused by가 try catch로 감싸기 전 처음 에러가 발생한 지점을 나타내 주기 때문이다.
'Error Handling' 카테고리의 다른 글
| [Error Handling] Spring Security 로그인 테스트에서 userParameter 설정 이슈 해결 (0) | 2025.09.12 |
|---|---|
| [Error Handling] EC2에서 Spring Boot 빌드 오류 해결 (0) | 2025.09.05 |
| [Error Handling] 도커 포트 포워딩 오류 해결 (0) | 2025.07.01 |
| [Error Handling] git push 인증 오류 해결 (0) | 2025.06.30 |
| [Error Handling] Lombok 오류 해결 (0) | 2025.06.25 |