NoClassDefFoundError 가 "제거된 API" 가 아니었던 건

Gradle 클래스로더 스코프 때문에 세 사이클을 날린 기록

2026-08-29신성욱GradleAndroid디버깅기록

Android 빌드가 설정 단계에서 죽었다. 메시지는 이랬다.

java.lang.NoClassDefFoundError: com/android/build/gradle/BaseExtension

BaseExtension 은 오래된 AGP API 다. 그래서 자연스럽게 이렇게 읽었다 — "AGP 가 이 클래스를 지웠고, 누군가 아직 참조하고 있다."

이 해석이 틀렸고, 여기서 세 사이클을 날렸다.

틀린 가정 위에서 한 일들

시도 결과
AGP 버전 교체 (8.7.3 / 8.13.2 / 9.3.2) 전부 동일하게 실패
Room · KSP · KAPT 제거 동일
빌드 스크립트의 레거시 DSL 제거 동일

세 번 다 "누가 그 클래스를 참조하나"를 찾는 일이었다. 가정 자체를 의심하지 않았다.

가정을 확인하는 데 걸린 시간: 10초

unzip -l gradle-8.13.2.jar | grep BaseExtension
31143  com/android/build/gradle/BaseExtension.class

클래스는 있었다. AGP 9.3.2 에도 있었다. 제거된 적이 없다.

NoClassDefFoundError 는 "클래스가 없다"가 아니라 "이 클래스로더에서 안 보인다" 는 뜻이다. 둘은 다르다.

진짜 원인

Gradle 은 플러그인을 프로젝트별 클래스로더 스코프에 올린다.

부모 클래스로더는 자식을 볼 수 없다. Kotlin 플러그인이 AGP 클래스를 찾을 방법이 없었다.

어떤 AGP 버전으로 바꿔도 안 고쳐진 이유가 이것이다. 애초에 버전 문제가 아니었다.

고친 방법

두 플러그인을 같은 스코프에 올린다.

// 루트 build.gradle.kts
plugins {
    kotlin("multiplatform") version "2.4.10" apply false
    id("com.android.application") version "8.13.2" apply false   // 추가
    kotlin("android") version "2.4.10" apply false                // 추가
    kotlin("plugin.compose") version "2.4.10" apply false         // 추가
}

곁가지: 그럴듯한 오답

같은 증상을 본 다른 사람이 스택트레이스의 검사 이름 (AgpWithBuiltInKotlinAppliedCheck)을 보고 이렇게 결론지었다.

최신 AGP 는 Kotlin 이 내장돼 있으니 kotlin("android") 를 제거하라.

이름만 보면 설득력이 있다. 실제로 해 보니 틀렸다.

Line 46: kotlin {          ^ Unresolved reference
Line 47:   jvmToolchain(17) ^ Unresolved reference: jvmToolchain

Kotlin 확장 자체가 사라진다. AGP jar 가 등록하는 플러그인 목록을 확인해 못을 박았다 — Kotlin 관련은 com.android.kotlin.multiplatform.library 하나뿐이고, 이건 KMP 라이브러리 모듈용이지 앱 모듈의 kotlin("android") 대체재가 아니다.

남는 교훈

가정을 고치기 전에 가정이 사실인지 먼저 잰다. "이 클래스는 제거됐다"를 확인하는 데 명령 한 줄이면 됐는데, 그걸 건너뛰고 세 번을 고쳤다.

에러 메시지는 증상이지 진단이 아니다. NoClassDefFoundError 는 "없다"고 말하지 않는다. "여기서 안 보인다"고 말한다.