gradle/gradle · error · InvalidUserCodeException

Could not add a component metadata rule for module '%s'.

Error message

Could not add a component metadata rule for module '%s'.

What it means

components { withModule(id, actionRule) } / withModule(id) { details -> ... } parses id into a ModuleIdentifier using a notation parser that accepts 'group:name' strings (and map notation). If the notation is unsupported — most commonly a 3-part 'group:name:version' string, but also null, a Dependency object, or any random type — the UnsupportedNotationException is wrapped in InvalidUserCodeException: "Could not add a component metadata rule for module '<id>'."

Source

Thrown at platforms/software/dependency-management/src/main/java/org/gradle/api/internal/artifacts/dsl/DefaultComponentMetadataHandler.java:115

        return this;
    }

    private ComponentMetadataHandler addClassBasedRule(SpecConfigurableRule ruleAction) {
        metadataRuleContainer.addClassRule(ruleAction);
        return this;
    }

    private <U> SpecRuleAction<? super U> createAllSpecRuleAction(RuleAction<? super U> ruleAction) {
        return new SpecRuleAction<>(ruleAction, Specs.satisfyAll());
    }

    private SpecRuleAction<? super ComponentMetadataDetails> createSpecRuleActionForModule(Object id, RuleAction<? super ComponentMetadataDetails> ruleAction) {
        ModuleIdentifier moduleIdentifier;

        try {
            moduleIdentifier = moduleIdentifierNotationParser.parseNotation(id);
        } catch (UnsupportedNotationException e) {
            throw new InvalidUserCodeException(String.format(INVALID_SPEC_ERROR, id == null ? "null" : id.toString()), e);
        }

        Spec<ComponentMetadataDetails> spec = new ComponentMetadataDetailsMatchingSpec(moduleIdentifier);
        return new SpecRuleAction<>(ruleAction, spec);
    }

    @Override
    public ComponentMetadataHandler all(Action<? super ComponentMetadataDetails> rule) {
        return addRule(createAllSpecRuleAction(ruleActionAdapter.createFromAction(rule)));
    }

    @Override
    public ComponentMetadataHandler all(Closure<?> rule) {
        return addRule(createAllSpecRuleAction(ruleActionAdapter.createFromClosure(ComponentMetadataDetails.class, rule)));
    }

    @Override
    @Deprecated

View on GitHub (pinned to 534f27719b)

Solutions

  1. Drop the version: withModule("org.springframework:spring-core").
  2. Use map notation if that reads better: withModule([group: 'org.springframework', name: 'spring-core']).
  3. If you need version-specific behavior, keep the rule on the module only and check details.id.version inside the rule body before acting.

Example fix

// before
components {
    withModule("org.springframework:spring-core:5.3.30") { // version -> unsupported notation
        it.allVariants { v -> v.withDependencies { deps -> deps.removeAll() } }
    }
}

// after
components {
    withModule("org.springframework:spring-core") {
        it.allVariants { v -> v.withDependencies { deps -> deps.removeAll() } }
    }
}
Defensive patterns

Strategy: validation

Validate before calling

def moduleId(String notation) {
    def parts = notation.split(':')
    assert parts.size() == 2 && parts.every { it } : "withModule id must be 'group:name' (no version), got: '$notation'"
    notation
}

Type guard

fun isModuleIdentifierNotation(id: Any?): Boolean =
    id is String && id.split(":").let { it.size == 2 && it.all(String::isNotBlank) }

Prevention

When it happens

Trigger: components { withModule("org.springframework:spring-core:5.3.30") { ... } } (version included), passing a Dependency or ExternalModule instance as id, passing null, or a map without group/name keys.

Common situations: Reusing a full GAV constant (shared with dependency declarations) as the withModule id; assuming withModule matches a specific version — it matches the module for ALL versions; copy-pasting coordinates from a dependencies block into the components block.

Related errors


AI-assisted analysis of gradle/gradle@534f27719b (2026-08-22). Data as JSON: /api/errors/b05f254ffcd647cf. Report an issue: GitHub.