Troubleshooting
Start with kmpTargetsInfo: it prints what resolved, which source won, and what registered, per module. For findings with fixes attached, kmpTargetsDoctor.
Resolution & installation
| Symptom |
Cause |
Fix |
Could not find com.rsicarelli:kmp-targets-gradle-plugin:<v> |
repository list doesn't cover the version's home |
releases live on mavenCentral(), -SNAPSHOTs only on https://central.sonatype.com/repository/maven-snapshots/ — add the right repo to pluginManagement (Installation) |
| Snapshot doesn't update |
Gradle caches changing modules for 24h |
./gradlew build --refresh-dependencies |
Plugin [id: 'com.rsicarelli.kmptargets'] was not found |
mavenCentral() missing from pluginManagement.repositories (it's not on the Plugin Portal) |
add it (Installation) |
Selection
| Symptom |
Cause |
Fix |
Build fails at configuration: Unknown target token '...' — did you mean ...? |
typo in kmptargets.targets; the parser is strict |
accept the suggestion; vocabulary is in kmpTargetsInfo or the reference |
Build fails: unknown key in kmp-targets.properties |
the config files accept only known kmptargets.* keys |
fix the key (the error suggests the nearest match) |
| Selection ignored / surprising value wins |
a higher-precedence source is set — often a stale kmp-targets.local.properties or an env var |
kmpTargetsInfo names the winning source; check the precedence chain |
| A module builds nothing |
empty overlap: selection ∩ supported = ∅ |
widen the selection or the module's supports { }; the empty-overlap advisory names the module |
| Every sync re-configures after changing selection |
each distinct value is its own configuration-cache entry — only the first build of a value misses |
expected; alternating between known values hits the cache (the trade-off) |
Registration
| Symptom |
Cause |
Fix |
androidTarget missing despite being selected + supported |
no Android Gradle plugin applied when supports { } ran |
apply com.android.library/com.android.application before supports { } (the ordering rule) |
compileCommonMainKotlinMetadata fails on a module that registered zero targets |
the inert-module trap: KGP materializes the metadata compilation even with no platform targets |
gate compilations on kmpTargets.registered().isEmpty() (recipe) |
Convention plugin misses targets when iterating kotlin.targets |
eager snapshot raced supports { } |
use onRegistered — it replays and fires deltas |
targetName throws |
called after supports { }, on a non-jvm leaf, or with a blank name |
rename must precede registration and only applies to jvm |
Building
| Symptom |
Cause |
Fix |
| Variant-resolution wall of text on an inter-module dependency |
dependency's supported set doesn't cover a target the dependent builds |
check both modules with kmpTargetsInfo; widen the dependency's supports { } (recipe) |
Variant-resolution wall of text on a compileDependencyFiles config after narrowing to android-only |
android consumers were resolving against producers' jvm fallback variant; a pure-android selection dropped it |
co-select jvm with android (kmptargets.targets=android,jvm) (recipe) |
Unresolved expect after narrowing to one iOS leaf |
minimal template collapsed the single-child iosMain your sources live in |
no-collapse |
| iOS compile/link fails on a Linux/Windows runner |
host can't compile the registered Apple target — registration is host-blind |
per-host selections (CI); the host advisory names the mismatch |
| CI job fails at configuration with an advisory's text |
strict mode promotes advisories to failures |
that's the point — fix the flagged configuration, or scope strict to lanes the host can fully compile |
apiCheck/BCV dumps disappear for some targets |
BCV ran in a narrowed lane and saw only registered targets |
run BCV tasks from a full-selection lane only (recipe) |
| KSP-generated symbols missing from commonMain |
only one target registered in this selection, so the shared commonMain metadata route (kspCommonMainKotlinMetadata) never ran |
move the codegen-consuming code to the target source set, or register a second target (recipe); kmpTargetsDoctor flags it as single-target KSP |
Still stuck? Open an issue with the kmpTargetsInfo output for the affected module — it carries exactly the state needed to diagnose.