Skip to content

Validate before you run

The question for this lesson: you’ve edited a 200-line pipeline. Before you run it over a million rows, how do you check it’s correct, without waiting for the whole run?

  • Use --dry-run to validate config structure and declared types without processing data, and know what it leaves for the real run.
  • Use --explain to print the execution plan and read it.
  • Decode a diagnostic E-code with explain --code.
clinker run customer_etl.yaml --dry-run

--dry-run parses your YAML, checks the config’s structure, validates your declared schema types, and resolves the output paths, then stops, without reading a single data row. If a required field is missing or a schema type doesn’t exist, you find out in a second.

Planning-only --dry-run validates the complete DAG and typechecks CXL against the declared schemas. It catches dangling input: references, unknown fields or methods, and incompatible types before reading records. It cannot prove that the actual file’s bytes satisfy the schema or that your business rule is right.

🌱 New here? — planning versus execution

Planning uses the pipeline and its declarations. To exercise real input, add -n 5: this reads at most five records per Source, evaluates the pipeline, and serializes preview bytes to stdout without opening configured Sink paths. --dry-run-output preview.csv selects an explicit preview file. A sample’s output-row count may differ after filters, aggregates, joins, or fan-out.

clinker run customer_etl.yaml --explain

--explain prints the execution plan in labelled sections (the CXL it compiled, the node graph, and how data flows), so you can confirm the pipeline does what you think before you run it. The full output is long; here are the three sections you’ll read most (trimmed):

=== Execution Plan ===
Mode: Streaming
Transforms: 1
Output projections: 1
DAG nodes: 3
=== CXL Expressions ===
Transform 'tagged':
emit is_active = status == "active"
=== DAG Topology ===
● [source] customers
│ [transform] tagged
│ [sink] results

When a run or dry-run fails, it prints an E-code. You don’t have to guess what it means; look any code up directly, with no config needed:

clinker explain --code E105

That prints a full explanation of the diagnostic: what it means, an example that triggers it, and how to fix it. E105, for instance, is “Channel binding references undeclared config key”: a channel file bound a config key the target pipeline never declared. The point isn’t to memorize codes. Whenever a run prints one, explain --code turns it into a plain explanation on the spot.

Run --dry-run on this one. Predict whether it passes, then check.

pipeline.yaml // editable

Now make --dry-run fail in two different ways. In the runner above, try two changes, one at a time, and predict the outcome of each before you re-run.

// quick check

What does `--dry-run` validate before reading any data?

Now put the tools together on a pipeline of your own. Author a small one from scratch: a csv source with a declared schema, one transform that emits a computed field, and an output. Then run the full pre-flight before any real run:

  1. clinker run mine.yaml --dry-run: does the config compile, and do the declared types check out?
  2. clinker run mine.yaml --explain: does === DAG Topology === show the nodes wired the way you intended, and does === CXL Expressions === show the formula you meant?
  3. Fix anything it surfaces, then run for real.

Predict, before you run: if you misspell a transform’s input:, both --dry-run and --explain reject the dangling reference during planning.