A teammate adds kotlin-reflect manually and pins it to a version different from the Kotlin compiler. What can go wrong, and how should the kotlin-reflect version be managed in a Gradle build?
answer
- kotlin-reflect must match the compiler/stdlib version
- Reads @Metadata — format evolves with the compiler
- Use kotlin("reflect") — version inherited from plugin
- Or constrain via kotlin-bom platform()
- Gradle resolves duplicates to highest — verify it matches
basics
~10 skotlin-reflect must match your Kotlin compiler version. A mismatch can cause incompatible-metadata warnings or runtime failures. Let the Kotlin Gradle plugin manage the version instead of hardcoding one.
solid answer
~40 skotlin-reflect reads the `@Metadata` the Kotlin compiler embeds, so its version must align with the compiler/stdlib version. If kotlin-reflect is *older* than the metadata it tries to read, it may not understand newer metadata and can throw or warn ('was compiled with a newer Kotlin version'); if it drifts the other way you get an inconsistent toolchain. Best practice: don't hardcode a version — the Kotlin Gradle plugin aligns kotlin-stdlib/kotlin-reflect to the plugin version automatically, so declare `implementation("org.jetbrains.kotlin:kotlin-reflect")` with no version, or use the Kotlin BOM (`platform("org.jetbrains.kotlin:kotlin-bom")`). Use `./gradlew dependencies` to confirm a single resolved Kotlin version, and rely on a failing resolution strategy if you want mismatches to fail the build. Frameworks pulling kotlin-reflect transitively can introduce a conflicting version, which Gradle resolves to the highest — verify it still matches your compiler.
code
kotlin · 10 lines// build.gradle.kts
plugins {
kotlin("jvm") version "2.1.0"
}
dependencies {
// Version-less: aligned to the Kotlin plugin automatically
implementation(kotlin("reflect"))
// Equivalent to: org.jetbrains.kotlin:kotlin-reflect:2.1.0
}go deeper
Adds kotlin-reflect but doesn't realize version must track the compiler.
Knows to match versions and uses kotlin("reflect") or the BOM.
Explains @Metadata coupling, Gradle highest-version resolution, and how to verify/enforce alignment.
Sets a build-platform convention (BOM/version catalog + failOnVersionConflict) so drift can't reach production.
## Why version alignment matters The Kotlin compiler embeds structural info in an `@Metadata` annotation on every generated `.class`. `kotlin-reflect` is the runtime that *reads* that metadata to build `KClass`/`KCallable` objects. Because the metadata format evolves with the compiler, **kotlin-reflect's version must be compatible with the compiler that produced your code** (and with `kotlin-stdlib`). Treat `kotlin-stdlib`, `kotlin-reflect`, and the compiler/Gradle-plugin version as one coupled set. ## What goes wrong on mismatch - **Old kotlin-reflect, newer code**: it may not understand newer metadata → warnings like 'class was compiled with a newer version of Kotlin' or, in worse cases, `UnsupportedOperationException`/incorrect results when reflecting. - **Mixed Kotlin versions on the classpath**: Gradle resolves duplicates to the *highest* version, which can silently upgrade or downgrade one artifact relative to the others, producing a subtly inconsistent toolchain. - **Transitive drift**: Spring Boot, Jackson's Kotlin module, etc. each declare a kotlin-reflect version; if your project pins a different one, conflict resolution decides the winner — not necessarily the one matching your compiler. ## How to manage the version correctly ### 1. Let the Kotlin Gradle plugin align it (preferred) The Kotlin Gradle plugin coordinates `kotlin-stdlib`/`kotlin-reflect` with the plugin version. Declare the dependency **without** a version: ```kotlin plugins { kotlin("jvm") version "2.x.y" } dependencies { implementation(kotlin("reflect")) // == org.jetbrains.kotlin:kotlin-reflect, version aligned } ``` `kotlin("reflect")` is the idiomatic helper and inherits the plugin's Kotlin version. ### 2. Or use the Kotlin BOM ```kotlin dependencies { implementation(platform("org.jetbrains.kotlin:kotlin-bom")) implementation("org.jetbrains.kotlin:kotlin-reflect") } ``` The BOM constrains all Kotlin artifacts to one consistent version. ### 3. Verify and enforce - `./gradlew dependencies --configuration runtimeClasspath` — confirm one resolved Kotlin version across stdlib/reflect. - A `resolutionStrategy { failOnVersionConflict() }` or `eachDependency` rule can force-align Kotlin artifacts and fail the build on drift. ## Practical guidance - Never hardcode a literal kotlin-reflect version that differs from your compiler. - After bumping the Kotlin plugin, you get the matching kotlin-reflect automatically — that's the point of not pinning it. - If only tests reflect, put it on `testImplementation` so prod stays smaller and there's one fewer version to align in the shipped artifact.
- Why is hardcoding kotlin-reflect to a fixed version risky across Kotlin upgrades?On every compiler bump you must remember to bump the pin too; forget, and reflect lags the metadata format, causing 'newer Kotlin version' warnings or reflective failures.
- If two libraries bring different kotlin-reflect versions, which wins?By default Gradle picks the highest version. You should verify it still matches your compiler, or use a resolutionStrategy to force-align Kotlin artifacts.
saying these in an interview costs you the question
- Hardcoding a kotlin-reflect version unrelated to the compiler
- Thinking kotlin-reflect version is independent of stdlib/compiler
- Not knowing kotlin("reflect") inherits the plugin version
- Ignoring transitive kotlin-reflect from frameworks
- Assuming Gradle picks the lowest version on conflict