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

  1. Migrate off @RuleSource entirely — rewrite the rule as a plain closure/Action rule or modern configuration APIs
  2. Ensure exactly one @Rule method with the correct subject and input parameter annotations for the target container
  3. 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

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


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