skip to content

A consumer build picks an unexpected variant or fails with 'no variants match' for a dependency. How does Gradle Module Metadata factor into diagnosing this?

level: seniorimportance: nice to knowfreq 25%

answer

  1. variant-aware matching needs exactly one match
  2. no-match vs ambiguity errors
  3. dependencyInsight shows requested vs available attrs
  4. read the .module for ground truth
  5. fix via component metadata rules / capabilities

basics

~20 s

GMM exposes the published variants and their attributes. When resolution fails, you compare the consumer's requested attributes against each variant's attributes — usually with dependencyInsight or by reading the .module file — and reconcile the mismatch via attributes, capabilities, or a component metadata rule.

solid answer

~40 s

Variant selection failures almost always trace back to attribute mismatches that GMM makes visible. The consumer configuration requests a set of attributes (usage, libraryelements, jvm.version, etc.); resolution must find exactly one matching variant in the dependency's GMM. If none match, you get 'no variants match'; if several match equally, an ambiguity error. Diagnose by running `gradle dependencyInsight --configuration runtimeClasspath --dependency foo`, which prints requested vs. available attributes, and by inspecting the published `.module` to see the real variant set and capabilities. Fixes include setting/aligning a consumer attribute, declaring a `requireCapability`, or, when the published metadata is wrong, patching it with a **component metadata rule** (`withVariant { ... }`) — without forcing the publisher to republish. If the library is POM-only, there's no rich variant info to match, which itself is often the root cause.

code

bash · 4 lines
bash
# Show why a variant was (not) selected — requested vs available attributes:
gradle dependencyInsight \
  --configuration runtimeClasspath \
  --dependency com.acme:lib

go deeper

for a junior

Recognize that the error is about variant/attribute matching and that dependencyInsight helps.

for a middle

Use dependencyInsight and read the .module to compare requested vs available attributes.

for a senior

Apply component metadata rules and capability resolution to fix mismatches without republishing.

for a principal

Treat recurring mismatches as an org-wide attribute-schema/publishing-policy problem and standardize platforms and GMM publication.

## Why GMM is central to diagnosis Gradle resolves by **variant-aware matching**: a consumer configuration declares requested attributes, and Gradle must select exactly one variant of each dependency whose attributes are compatible. GMM is where those producer-side variants and attributes are declared, so it is the ground truth you inspect when selection misbehaves. ## The two failure shapes 1. **No variants match** — no published variant satisfies the requested attributes (e.g. consumer wants `org.gradle.jvm.version=11` but the library only publishes a JDK 17 variant). 2. **Ambiguity** — more than one variant matches equally and Gradle can't disambiguate. ## Diagnostic tools - `gradle dependencyInsight --configuration runtimeClasspath --dependency com.acme:lib` — shows the requested attributes and the candidate variants with their attributes, plus *why* each was rejected. - Reading the published `.module` directly (it's in the cache under the Gradle user home, or fetchable from the repo) reveals the actual variant names, attributes, capabilities, and files. - `gradle dependencies` / build scans for the broader graph. ## Fixes ```kotlin // 1. Patch wrong/missing attributes on a published variant without republishing: dependencies { components { withModule("com.acme:lib") { withVariant("runtime") { attributes { attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 11) } } } } } ``` - **Component metadata rules** (`components { withModule(...) { ... } }`) let you add/override attributes, declare capabilities, or fix dependencies on third-party GMM/POM metadata locally. - **Capabilities**: if two modules provide the same capability (e.g. `groovy` vs `groovy-all`), you resolve the conflict by choosing one via `resolutionStrategy.capabilitiesResolution` or `requireCapability`. ## The POM-only trap If the dependency publishes **no** `.module`, Gradle synthesizes minimal variants from the POM. That's a frequent root cause of 'no variants match' for niche attributes — the rich info simply isn't there, and the fix is a component metadata rule that injects the missing attributes. ## Architectural takeaway At scale, recurring variant mismatches signal an attribute-schema misalignment across an org's libraries — best addressed by standardizing platform/attribute conventions and publishing all internal libs with GMM.

  • Which command shows requested vs available attributes for a failing dependency?
    `gradle dependencyInsight --configuration <cfg> --dependency <group:name>` prints the requested attributes and each candidate variant with the rejection reason.
  • The library is POM-only and a niche attribute won't match — what's the fix?
    Add a component metadata rule (`components { withModule(...) { withVariant(...) { attributes { ... } } } }`) to inject the missing attribute locally, without republishing the artifact.
  • What causes an 'ambiguity' (rather than 'no match') error?
    Two or more published variants match the requested attributes equally, so Gradle cannot pick one; you disambiguate by adding a discriminating attribute or capability.

saying these in an interview costs you the question

  • Jumping to forceful version overrides instead of reading the actual variant attributes in the .module.
  • Assuming you must get the publisher to republish — component metadata rules fix third-party metadata locally.

context