Skip to main content

Validations

Validations let a rule author declare additional pass/fail checks that Buck2 enforces whenever the target is in a requested build's transitive closure. A validation succeeds when the action that produces its result artifact writes a JSON document signalling success; otherwise the build fails.

When validations run

A validation attached to target //A:a runs whenever a buck2 build or buck2 test request resolves a graph that contains //A:a as a transitive dependency. Validations execute in parallel with the rest of the build — they only need to finish before Buck2 reports the requested target complete.

Validations are not re-run when the producing action's inputs are unchanged (standard Buck2 caching).

Declaring a validation

Return a ValidationInfo provider from your rule's impl, populated with one or more ValidationSpec values:

def _my_rule_impl(ctx):
report = ctx.actions.declare_output("schema_report.json")
ctx.actions.run(
cmd_args("validate-schema", "--out", report.as_output(), ctx.attrs.src),
category = "schema_validation",
)
return [
DefaultInfo(default_output = ctx.attrs.src),
ValidationInfo(validations = [
ValidationSpec(
name = "schema",
validation_result = report,
),
]),
]

Constraints:

  • Each spec needs a non-empty name, unique within the ValidationInfo.
  • validation_result must be a build artifact (not a source file).
  • The provider must contain at least one spec.

Writing the validator

The validator is just an action — any binary that writes a JSON file in the expected schema works. The schema:

{
"version": 1,
"data": {
"status": "success",
"message": "Optional human-readable detail."
}
}
FieldTypeRequiredNotes
versionintyesCurrently 1.
data.statusstringyes"success" or "failure".
data.messagestringnoShown to the user; supply on failure.

Buck2 reports three distinct errors if the file is malformed: invalid JSON, incompatible version, or schema mismatch.

Additional fields outside the required ones are tolerated and ignored by Buck2 — both at the top level (alongside version / data) and inside data (alongside status / message). This is a deliberate extension point: attach structured debug or diagnostic info (timings, tool versions, dashboard URLs, anything you want to keep with the verdict) and Buck2 will pass it through unread.

The required fields still define the machine contract — keep them stable. Unstructured logs belong in stderr or a separate artifact, not in this file.

Required vs optional validations

Pass optional = True to a ValidationSpec to mark it advisory:

ValidationSpec(name = "slow_lint", validation_result = report, optional = True)

Optional validations are skipped by default. Users opt in per-name on the CLI:

buck2 build //A:a --enable-optional-validations slow_lint

Use this for expensive or noisy checks you don't want to gate every build on.