Java에서 자주 발생하는 ClassNotFoundException과 NoClassDefFoundError의 차이를 정리하고, 각각의 대표 원인과 해결 방법을 체크리스트로 제공합니다. 의존성 누락, 런타임 클래스패스 문제, WAR/JAR 배포 환경, 톰캣 로딩 이슈까지 실무 사례 중심으로 정리했습니다.

ClassNotFoundException / NoClassDefFoundError 차이와 해결 (원인/대응 총정리)
자바 프로젝트를 하다 보면 꼭 한 번은 만나게 되는 에러가 있습니다.
- java.lang.ClassNotFoundException
- java.lang.NoClassDefFoundError
둘 다 “클래스를 못 찾는다”처럼 보이는데, 의미와 원인/해결 방향이 완전히 다릅니다.
이 글에서는 두 에러의 차이를 실무 기준으로 깔끔하게 정리해보겠습니다.
1. 두 에러의 핵심 차이 한 줄 요약
ClassNotFoundException
“지금 로딩하려고 했는데 클래스패스에서 클래스를 못 찾음” (대부분 클래스패스/의존성 누락)
NoClassDefFoundError
“예전에 로딩/컴파일은 됐는데, 실행 중에 갑자기 클래스 정의를 못 가져옴” (대부분 런타임 환경 문제/의존성 충돌)
2. ClassNotFoundException이란?
ClassNotFoundException은 체크 예외(Exception) 입니다.
보통 아래처럼 동적으로 클래스를 로딩할 때 많이 발생합니다.
이때 com.example.Foo가 런타임 클래스패스에 없으면 발생합니다.
✅ 대표 상황
- 라이브러리(jar)가 아예 빠짐
- IDE에서는 되는데 서버 배포하면 빠짐 (WAR에 미포함)
- 클래스명 오타 / 패키지 경로 변경
- 리플렉션으로 로딩하는 문자열이 잘못됨
3. NoClassDefFoundError란?
NoClassDefFoundError는 이름 그대로 Error 입니다. (예외가 아니라 에러)
뜻은:
JVM이 어떤 클래스를 “이미 로딩하려고 시도했거나 로딩했던 적이 있는데”,
실행 시점에 그 클래스 정의를 사용할 수 없게 됐다.
즉 “클래스가 없다”라기보다, 실행 환경에서 클래스를 정상적으로 사용할 수 없는 상태가 핵심입니다.
✅ 대표 상황
- A 클래스는 있는데, A가 의존하는 B 클래스가 없음 → 실행 중 터짐
- 버전 충돌로 메소드/필드가 달라서 로딩 실패
- 서버(ClassLoader) 격리 문제(톰캣, WAS)
- static 초기화 블록에서 예외가 터져 로딩 실패 → 이후 NoClassDefFoundError로 보일 수 있음
4. 차이점 비교표
| 타입 | Exception(체크 예외) | Error |
| 발생 시점 | 클래스 로딩 “시도” 시점 | 클래스 로딩 실패/정의 사용 불가 |
| 흔한 원인 | 클래스패스에 아예 없음 | 의존성 누락/버전 충돌/초기화 실패 |
| 해결 방향 | jar 포함/클래스패스 수정 | 의존성 트리 정리/버전 충돌 해결/배포 구조 점검 |
5. 발생 원인 TOP 6 (실무)
원인 1) 의존성(jar) 누락
- 로컬에서는 있는데 서버 WAR/JAR에 빠짐
✅ 확인: 빌드 산출물에 jar가 포함됐는지
원인 2) 버전 충돌 (가장 흔한 NoClassDefFoundError 원인)
예: A 라이브러리는 commons-logging 1.2를 기대하는데
런타임에는 1.0이 들어가 있다면 로딩 중 실패할 수 있습니다.
✅ 해결: dependency tree 확인
Maven:
Gradle:
원인 3) 톰캣/WAS 클래스 로더 문제
- WEB-INF/lib에 있어야 할 jar가 서버 공용 lib에 있거나
- 반대로 서버 lib가 먼저 로딩되어 충돌
✅ 해결:
- jar를 한 군데로 정리
- 서버 공용 lib에 넣은 jar는 최소화
원인 4) packaging 문제 (war/jar)
- war로 배포해야 하는데 jar로 돌리거나, 그 반대
- provided scope 설정이 꼬여서 배포 산출물에 빠짐
✅ Maven 예: provided 조심
이걸 걸면 배포물에 포함 안 될 수 있음 (서버가 제공한다고 가정)
원인 5) 빌드/IDE 캐시 꼬임
- “클래스 파일은 있는데 못 찾음”이라고 느껴질 때 의외로 많음
✅ 해결:
- Clean / Rebuild
- IDE 캐시 정리
원인 6) static 초기화 실패 → 이후 NoClassDefFoundError
예:
처음 로딩이 실패하면, 이후 참조 시점에 NoClassDefFoundError로 보일 수 있습니다.
✅ 해결: 최초 원인 로그(맨 처음 터진 스택트레이스)부터 확인
6. 해결 체크리스트 (바로 적용)
✅ 1) 로그에서 “진짜 최초 원인” 찾기
- NoClassDefFoundError는 뒤에 따라오는 2차 증상인 경우가 많음
✅ 2) 빌드 산출물에 jar 포함 확인
- JAR: BOOT-INF/lib
- WAR: WEB-INF/lib
✅ 3) dependency tree로 버전 충돌 확인
- 중복 라이브러리 제거 / 버전 고정
✅ 4) 톰캣 공용 lib vs 앱 lib 충돌 확인
- 서버 lib에 넣은 jar가 우선 로딩될 수 있음
✅ 5) Clean build / 캐시 삭제 후 재배포
- “어제 되던게 오늘 안됨”이면 효과 큼
7. 톰캣 배포에서 자주 터지는 케이스 (실무 팁)
- 운영서버 lib에 오래된 jar가 남아있어 충돌
- 여러 WAR들이 같은 라이브러리를 서로 다른 버전으로 사용
- 클래스패스가 꼬여서 어떤 서버에서는 되고 어떤 서버에서는 안됨
✅ 이런 경우 해결은 “정리”가 답:
- 공용 lib 최소화
- 애플리케이션별 WEB-INF/lib로 통일
- 버전 고정(BOM/의존성 관리)
결론
- ClassNotFoundException: 클래스패스에 아예 없음 → jar 누락/경로/오타 점검
- NoClassDefFoundError: 로딩/정의 사용 실패 → 의존성 충돌/초기화 실패/배포환경 점검