Troubleshooting
Troubleshooting
[ComposeTvos] WARNING: tvOS variant discovery found nothing for N redirect-eligible module(s)
This means the plugin looked for a tvOS klib (official first, then the dev.sajidali fork)
for one or more modules and found neither, for the exact group:artifact:version it was asked
about. Two common causes:
- A real gap — the fork hasn’t published that version/group yet (check the
version matrix and the manifest), or the version needs an entry in
composeTvos.versionMappings. - A pre-conflict-resolution candidate version.
ComponentMetadataRules fire on every version node Gradle’s resolution engine touches while resolving a graph, not just the winning version after conflict resolution — so a losing candidate version (one nothing ends up actually depending on) can legitimately show up in this list even though your build’s resolved graph never touches it. If your build otherwise succeeds and the modules named don’t ring a bell, this is very likely why.
Set composeTvos.strictMode.set(true) temporarily and inspect the resulting exception message
together with ./gradlew :dependencies --configuration <tvosConfigurationName> to see whether
the named module survives conflict resolution.
strictMode
By default, the WARN block above is only a warning, not a build failure. Set
composeTvos.strictMode.set(true) if you’d rather the build fail loudly than warn — useful in
CI once you’ve confirmed your resolved graph is clean. Both the WARN block and strictMode’s
GradleException only ever fire for a project that actually declares a tvOS Kotlin target.
Clearing the cache
Both the variant-discovery cache and the version-manifest cache live under GRADLE_USER_HOME,
resolved from whichever GRADLE_USER_HOME (or --gradle-user-home) the invoking Gradle actually
used — never hardcoded to ~/.gradle — so isolated/CI/TestKit invocations get isolated caches
automatically:
- Variant-discovery cache:
<gradleUserHome>/compose-tvos-redirect-cache-v4/ - Version-manifest cache:
<gradleUserHome>/compose-tvos-redirect-cache-v4/version-manifest/
If a fork publish changes shape (new tvOS variants, a version bump) and the plugin still reports stale results, clear the on-disk cache:
rm -rf "$(./gradlew properties -q --property gradleUserHomeDir | awk '{print $2}')/compose-tvos-redirect-cache-v4"
or simply delete ~/.gradle/compose-tvos-redirect-cache-v4 if you use the default
GRADLE_USER_HOME.
--refresh-dependencies forces a fresh version-manifest fetch without clearing the
variant-discovery cache.
Offline behavior
With --offline, the plugin never opens a network connection: the version manifest and
per-artifact variant-discovery results are served from their on-disk caches only (fresh or
stale — stale-while-offline is preferred over failing the build), and a coordinate with no
cached entry degrades to an empty result (treated the same as “no tvOS variant found”), never a
hard failure.
Known exclusions
There are no outstanding gaps in the covered dependency groups as of this writing — the
compose.material3.adaptive family and androidx.window:window-core (formerly excluded) are
now published by the fork and covered by the same-version convention with no extra
configuration. See Supported versions for the full matrix.
The one target that remains unsupported is tvosX64 (the legacy Intel tvOS simulator) — the
fork does not build it, and this plugin does not redirect it. Use tvosSimulatorArm64 for
simulator builds instead.
Plugin does not resolve
Version 1.1.0+ resolves from the
Gradle Plugin Portal with no
pluginManagement configuration (it is also on Maven Central). If resolution fails, check for
a pluginManagement.repositories block of your own that omits gradlePluginPortal() — once
you declare that block, Gradle stops adding the Portal implicitly, so keep both
gradlePluginPortal() and mavenCentral() in it. Do not pin version 1.0.0: it predates the
published artifact ecosystem and configures nothing (upgrade to 1.1.0).
Migrating from a pre-plugin “shadow” repository
If your project previously obtained tvOS Compose by publishing patched org.jetbrains.*
artifacts into mavenLocal() or a vendored/local Maven directory (the “shadow” approach used
before this plugin existed), remove those org/jetbrains/** entries before adopting the
plugin (keep any third-party artifacts, e.g. your own koin/coil tvOS builds — only the
Compose shadow must go).
Why: the plugin deliberately prefers official artifacts whenever they already provide a tvOS
variant (“official-first”). It cannot distinguish a genuine upstream tvOS publish from your own
older shadow publish sitting in a repository you declared — so the stale shadow wins, no
injection happens for those modules, and your dependency graph silently mixes two Compose
lineages. The typical symptom is not a resolution error but a link-time failure with
duplicate IR symbols (e.g. IrPropertySymbolImpl is already bound) once modules from both
lineages meet in one binary.
Artifacts not found
Ensure your repositories include Maven Central (and, for the very latest fork publishes ahead of
a Central sync, mavenLocal()):
// settings.gradle.kts
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
}
}