{"record":{"id":"8cedf464944c92e7","repo":"gradle/gradle","slug":"the-closure-provided-is-not-valid-as-a-rule-for","errorCode":null,"errorMessage":"The closure provided is not valid as a rule for '%s'.","messagePattern":"The closure provided is not valid as a rule for '(.+?)'\\.","errorType":"validation","errorClass":"InvalidUserCodeException","httpStatus":null,"severity":"error","filePath":"platforms/software/dependency-management/src/main/java/org/gradle/internal/rules/DefaultRuleActionAdapter.java","lineNumber":45,"sourceCode":"    @SuppressWarnings(\"InlineFormatString\")\n    private static final String INVALID_ACTION_ERROR = \"The action provided is not valid as a rule for '%s'.\";\n    @SuppressWarnings(\"InlineFormatString\")\n    private static final String INVALID_RULE_SOURCE_ERROR = \"The rule source provided does not provide a valid rule for '%s'.\";\n\n    private final RuleActionValidator ruleActionValidator;\n    private final String context;\n\n    public DefaultRuleActionAdapter(RuleActionValidator ruleActionValidator, String context) {\n        this.ruleActionValidator = ruleActionValidator;\n        this.context = context;\n    }\n\n    @Override\n    public <T> RuleAction<? super T> createFromClosure(Class<T> subjectType, Closure<?> closure) {\n        try {\n            return ruleActionValidator.validate(new ClosureBackedRuleAction<>(subjectType, closure));\n        } catch (RuleActionValidationException e) {\n            throw new InvalidUserCodeException(String.format(INVALID_CLOSURE_ERROR, context), e);\n        }\n    }\n\n    @Override\n    public <T> RuleAction<? super T> createFromAction(Action<? super T> action) {\n        try {\n            return ruleActionValidator.validate(new NoInputsRuleAction<>(action));\n        } catch (RuleActionValidationException e) {\n            throw new InvalidUserCodeException(String.format(INVALID_ACTION_ERROR, context), e);\n        }\n    }\n\n    @Override\n    @Deprecated\n    public <T> RuleAction<? super T> createFromRuleSource(Class<T> subjectType, Object ruleSource) {\n        try {\n            return ruleActionValidator.validate(RuleSourceBackedRuleAction.create(ModelType.of(subjectType), ruleSource));\n        } catch (RuleActionValidationException e) {","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/gradle/gradle/blob/534f27719b66953f95cc907aae7f2c1b12f5482d/platforms/software/dependency-management/src/main/java/org/gradle/internal/rules/DefaultRuleActionAdapter.java#L27-L63","documentation":"DefaultRuleActionAdapter.createFromClosure wraps any RuleActionValidationException raised while building a closure-based rule action into an InvalidUserCodeException: 'The closure provided is not valid as a rule for <context>'. The context string names the rule container/DSL where the closure was declared. The real reason is in the cause: typically a wrong first-parameter type or an input parameter of an unsupported type.","triggerScenarios":"Adding a closure rule to a rule-based container (e.g. legacy native/software-model DSLs built on RuleActionAdapter) whose closure signature fails validation — bad subject parameter type (1247) or disallowed input parameter types (1251).","commonSituations":"Authoring or upgrading software-model-era build logic; migrating between Gradle versions where allowed rule input types changed; copy-pasting example closures into a different rule container.","solutions":["Read the caused-by RuleActionValidationException in the stack trace to see the concrete signature problem","Fix the closure's first parameter to match the rule subject type","Restrict extra closure parameters to the input types allowed by that container (listed in the underlying validation message)"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    adapter.createFromClosure(subjectType, closure)\n} catch (org.gradle.api.InvalidUserCodeException e) {\n    def cause = e.cause\n    if (cause instanceof org.gradle.internal.rules.RuleActionValidationException) {\n        // fix the closure signature per cause.message\n        throw new GradleException('Invalid rule closure: ' + cause.message, e)\n    }\n    throw e\n}","preventionTips":["Match closure first-parameter types to the rule subject before registering","Check allowed input types for the container before adding extra parameters","Always inspect the caused-by chain of InvalidUserCodeException from rule APIs"],"tags":["gradle","rules","closure","user-code","legacy-software-model"],"backgroundTag":"invalid-rule-declaration","analyzedSha":"534f27719b66953f95cc907aae7f2c1b12f5482d","analyzedAt":"2026-08-22T08:09:12.375Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}