Finding out why a Dependency was Requested

I wanted to write a short post about how to find the reason for a particular version of a dependency to be selected by Gradle.

Today, while building our app, we started getting this error:

The minCompileSdk (31) specified in a
dependency's AAR metadata (META-INF/com/android/build/gradle/aar-metadata.properties)
is greater than this module's compileSdkVersion (android-30).
Dependency: androidx.core:core:1.7.0-alpha02.
AAR metadata file: /Users/ahmedre/.gradle/caches/transforms-3/3a90b660583f6aafd513bafe95732d86/transformed/core-1.7.0-alpha02/META-INF/com/android/build/gradle/aar-metadata.properties.

The error makes sense, but my question was, “who pulls in androidx.core:core:1.7.0-alpha02 - we shouldn’t be using alpha dependencies at the moment, so where is this coming from?”

The first place to look was through Gradle’s dependency target -

./gradlew :app:dependencies --configuration releaseRuntimeClasspath > deps.txt

Taking a snippet from this file, I see many things like:

androidx.core:core-ktx:1.1.0 -> 1.7.0-alpha02 (*)
androidx.core:core-ktx:1.6.0 -> 1.7.0-alpha02 (*)
...

Looking through this, I can see indeed that androidx.core:core is being updated from various other versions to 1.7.0-alpha02, but I don’t know why. I did some searching, and today I learned about the dependencyInsight target. Quoting the Gradle documentation:

The dependencies report provides you with the raw list of dependencies but does not explain why they have been selected or which dependency is responsible for pulling them into the graph.

This is run by doing something like:

./gradlew :app:dependencyInsight --dependency "androidx.core:core-ktx" --configuration "releaseRuntimeClasspath" > insight.txt

Looking at this, I get a good breakdown of which versions are being pulled and why - one of the blocks I see tells me the culprit:

androidx.core:core-ktx:+ -> 1.7.0-alpha02
+--- com.depedency:redacted:14.27.6

This is the culprit! The publisher of this dependency seems to have added an androidx.core:core-ktx:+ dependency. I checked and this was indeed the case. Mystery solved!

The next question was, how do we avoid having this happen again? Some more searching lead me to this post in the Gradle documentation, which suggests the usage of the failOnDynamicVersions(). We can also prevent snapshots by doing failOnChangingVersions(). Awesome!