gradle/gradle · error · InvalidUserCodeException
The rule source provided does not provide a valid rule for '
Error message
The rule source provided does not provide a valid rule for '%s'.
What it means
The deprecated RuleSource path: createFromRuleSource builds a RuleSourceBackedRuleAction from a class with @Rule-annotated methods and validates it. Any validation failure (missing/incorrect rule annotations, bad subject or parameter types) is wrapped as InvalidUserCodeException — 'The rule source provided does not provide a valid rule for <context>'. RuleSource is part of the removed software model, so builds still using it are on legacy ground.
Source
Thrown at platforms/software/dependency-management/src/main/java/org/gradle/internal/rules/DefaultRuleActionAdapter.java:64
}
}
@Override
public <T> RuleAction<? super T> createFromAction(Action<? super T> action) {
try {
return ruleActionValidator.validate(new NoInputsRuleAction<>(action));
} catch (RuleActionValidationException e) {
throw new InvalidUserCodeException(String.format(INVALID_ACTION_ERROR, context), e);
}
}
@Override
@Deprecated
public <T> RuleAction<? super T> createFromRuleSource(Class<T> subjectType, Object ruleSource) {
try {
return ruleActionValidator.validate(RuleSourceBackedRuleAction.create(ModelType.of(subjectType), ruleSource));
} catch (RuleActionValidationException e) {
throw new InvalidUserCodeException(String.format(INVALID_RULE_SOURCE_ERROR, context), e);
}
}
}
View on GitHub (pinned to 534f27719b)
Solutions
- Migrate off @RuleSource entirely — rewrite the rule as a plain closure/Action rule or modern configuration APIs
- Ensure exactly one @Rule method with the correct subject and input parameter annotations for the target container
- Pin the last Gradle version supporting your RuleSource plugin while migrating
Defensive patterns
Strategy: try-catch
Validate before calling
import org.gradle.model.Rule
// sanity-check a RuleSource before registration: exactly one @Rule method,
// first parameter = expected subject type
static boolean looksLikeValidRuleSource(Class<?> ruleSource, Class<?> subject) {
def ruleMethods = ruleSource.declaredMethods.findAll { it.isAnnotationPresent(Rule) }
ruleMethods.size() == 1 && ruleMethods[0].parameterTypes.length > 0 &&
ruleMethods[0].parameterTypes[0].isAssignableFrom(subject)
} Try / catch
try {
adapter.createFromRuleSource(subjectType, ruleSourceInstance)
} catch (org.gradle.api.InvalidUserCodeException e) {
throw new GradleException('RuleSource ' + ruleSourceInstance.class.name + ' does not provide a valid @Rule for ' + subjectType.simpleName, e)
} Prevention
- Migrate away from @RuleSource — it belongs to the removed software model
- Annotate exactly one @Rule method with the correct subject parameter
- Keep legacy RuleSource plugins pinned to Gradle versions that support them
When it happens
Trigger: Calling a rule container API with a @RuleSource-annotated class whose methods do not conform to what RuleSourceBackedRuleAction.create expects for the given subject type.
Common situations: Maintaining pre-software-model-removal plugins; porting old samples; Gradle upgrades that tightened or removed RuleSource support.
Related errors
- The closure provided is not valid as a rule for '%s'.
- The action provided is not valid as a rule for '%s'.
- Rule may not have an input parameter of type: %s.
- Direct instantiation of a BaseBinarySpec is not permitted. U
- Capability resolution rule failed with an error
AI-assisted analysis of gradle/gradle@534f27719b (2026-08-22).
Data as JSON: /api/errors/3af70f864b10f67c.
Report an issue: GitHub.