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.

Be honest about its reach, though: --dry-run validates the structure and declared types before reading data. Deeper logic errors (a dangling input: that names a node which isn’t there, an unknown field or method inside a CXL expression) aren’t caught here. Those surface when you actually run, because they depend on the data flowing through. So treat --dry-run as the fast first gate, not a full proof of correctness.

🌱 New here? — why it's instant

Validation doesn’t touch your data. Clinker checks the shape of the job (the config structure, the declared schema types, the resolved outputs), which is fast no matter how big the file is. Only a real run reads rows. So --dry-run costs the same whether your file has 10 rows or 10 million.

You can also process just the first few rows to sanity-check output: --dry-run -n 5 runs 5 records to stdout instead of the output file.

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
│ [output] 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, and find the one break it lets through. 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:, which step catches it? Not --dry-run. A dangling input: is a wiring error, not a declared-type error, so it passes dry-run. Reading the --explain topology is what catches it before you waste a full run.