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
@DeprecatedView on GitHub (pinned to 534f27719b)
Solutions
- Drop the version: withModule("org.springframework:spring-core").
- Use map notation if that reads better: withModule([group: 'org.springframework', name: 'spring-core']).
- 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
- Keep separate constants for module identifiers ('g:n') and dependency coordinates ('g:n:v'); never reuse one for the other.
- Remember withModule matches every version of the module — version filtering belongs inside the rule body.
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
- Name must not be null!
- Invalid format for capability: '{}'. The correct notation is
- Invalid format: '{}'. The correct notation is a 3-part group
- Invalid format: '{}'. Group, name and version cannot be empt
- There was an error while evaluating a component metadata rul
AI-assisted analysis of gradle/gradle@534f27719b (2026-08-22).
Data as JSON: /api/errors/b05f254ffcd647cf.
Report an issue: GitHub.