Did not resolve org.jetbrains.kotlin:kotlin-stdlib-common:2.2.0 which is part of the dependency lock state

Summary

A failed release build occurred due to unresolved dependency org.jetbrains.kotlin:kotlin-stdlib-common:2.2.0, which was locked in myLibrary‘s Gradle lockfile. The error surfaced during R8 minification when the locked version conflicted with transitive dependency resolution in a multi-module Android project.

Root Cause

The failure resulted from:

  • Dependency locking applying to Android runtime configurations, which rely on implicit Kotlin dependencies.
  • Lockfiles capturing kotlin-stdlib-common:2.2.0 during resolution, but Android projects implicitly use JDK variants (e.g., kotlin-stdlib-jdk8).
  • R8 resolution requiring dependencies absent in the lockfile during the minification task (minifyLibDefaultReleaseWithR8).

Why This Happens in Real Systems

  • Android Gradle Plugin (AGP) uses derived configurations (e.g., *RuntimeClasspath) incompatible with strict locking.
  • Transitive Kotlin dependencies are implicitly injected by Kotlin plugin but locked unintentionally.
  • Multi-project builds compound resolution mismatches when locked dependencies conflict across modules.

Real-World Impact

If unaddressed:

  • Release builds fail unpredictably despite successful debug builds.
  • Dependency version drift occurs when lockfiles override Android’s dependency substitutions.
  • Critical toolchain libraries (Kotlin stdlib) become unresolvable, halting deployments.

Example or Code

Selective locking setup (applied globally in root build.gradle):

dependencyLocking {  
  lockAllConfigurations()  
  lockMode = LockMode.STRICT  

  // Explicitly skip Android runtime configurations  
  unlockAllConfigurations()  
  lockConfigurations = [  
    "api",  
    "implementation",  
    "compileClasspath",  
    "annotationProcessor",  
    "testImplementation"  
  ]  
}

How Senior Engineers Fix It

  1. Avoid locking Kotlin stdlib:
    • Explicitly exclude Kotlin artifacts from lockfiles:
      configurations.all {  
        resolutionStrategy {  
          componentSelection {  
            all { ComponentSelection selection ->  
              if (selection.candidate.group == 'org.jetbrains.kotlin' && selection.candidate.module.contains('stdlib')) {  
                selection.reject("Excluding Kotlin stdlib from locking")  
              }  
            }  
          }  
        }  
      }
  2. Restrict locking to explicit configurations:
    • Lock only compile/declaration configurations (api, implementation) and unlock implicit or runtime configurations.
  3. Use dependency constraints to implicitly manage Kotlin versions:
    dependencies {  
      constraints {  
        implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.0")  
        implementation("org.jetbrains.kotlin:kotlin-stdlib-common:1.9.0")  
      }  
    }
  4. Centralize dependency versions using Gradle version catalogs to avoid conflicts.

Why Juniors Miss It

  • Unfamiliarity with Android’s complex configuration hierarchy, particularly runtimeClasspath derivations.
  • Overlooking implicit Kotlin dependencies injected by plugins.
  • Misapplying generic locking patterns to dynamic Android projects without platform-specific filters.
  • Debug vs. release configuration discrepancies hiding locking oversights until minification tasks execute.
  • Assuming locking applies uniformly without considering AGP’s dependency resolution quirks.

Leave a Comment