WorkingDirectory icon
Write icon
Commands icon
Commands icon

Validate CSV Files with Shell and Python Scripts in a Working Directory

Kestra flow that validates a CSV in two stages inside a WorkingDirectory, a bash row-count check then a pandas required-columns check, with scripts inlined via inputFiles.

Categories
Infrastructure

Bad files should fail loudly at the front door, not three tasks deep into a load. This Kestra blueprint runs a two-stage validation gate inside a single working directory: a bash script does the cheap structural checks (file exists, rows present, header preview), then a Python script loads the file with pandas and fails the execution if required columns are missing. Both scripts are inlined through inputFiles, so the flow deploys and runs on any Kestra instance with nothing to sync first.

How it works

  1. The my_working_dir task (io.kestra.plugin.core.flow.WorkingDirectory) gives all child tasks one shared filesystem, following the one-working-directory-per-flow best practice.
  2. The create_csv task (io.kestra.plugin.core.storage.Write) writes a sample users CSV to internal storage; in production you would replace this with your real extract.
  3. The shell_check task (io.kestra.plugin.scripts.shell.Commands) receives check.sh via inputFiles and runs it with the CSV's URI as argument. Kestra materializes internal storage URIs referenced in commands as local files, so the script just reads a path. It prints line counts and the header, and exits non-zero on a missing file.
  4. The python_validate task (io.kestra.plugin.scripts.python.Commands) runs pre_process.py in a python:3.13-slim container with pandas and click declared as dependencies. The click CLI takes --input-file and --column-names, logs row and column stats, and raises if any required column is absent, failing the task and therefore the flow.

What you get

  • A fail-fast quality gate you can drop in front of any loading or transformation pipeline.
  • Cheap checks first, expensive checks second: bash catches empty or missing files before a container ever spins up pandas.
  • Fully self-contained deployment; the scripts travel inside the flow YAML.
  • A clean upgrade path to shared scripts: swap inputFiles for namespaceFiles once the scripts live as namespace files synced from Git.

Who it's for

  • Data engineers guarding warehouse loads against malformed vendor or partner files.
  • Analytics teams that keep getting burned by renamed or dropped columns upstream.
  • Anyone packaging existing validation scripts into orchestrated, observable steps.

Why orchestrate this with Kestra

Validation scripts scattered across servers fail silently or, worse, get skipped. In Kestra each check is a task with its own logs, exit-code semantics, and container image, and the working directory plus internal storage handle file movement without shared volumes or scp. Declaring dependencies on the Python task replaces requirements.txt shipping, and the whole gate is versioned YAML: review it, revision it, and reuse it as a subflow in every ingestion pipeline you own.

Prerequisites

  • A Kestra instance whose worker can run Docker for the python:3.13-slim container.
  • Network access to pull the container image and install the two pip dependencies on first run.

Secrets

No secrets are required. If the real CSV comes from an authenticated source, fetch it with a dedicated task using {{ secret('NAME') }} credentials and pass its URI to the validators.

Quick start

  1. Import this flow into the company.team namespace and execute it.
  2. Read shell_check logs for the row count and header, then python_validate logs for the pandas column report.
  3. Break it on purpose: remove email from the create_csv header and rerun to watch the Python stage fail with a precise error.
  4. Replace create_csv with your real file source and update --column-names to your schema.

How to extend

  • Move the scripts to namespace files synced with io.kestra.plugin.git.SyncNamespaceFiles, then reference them with namespaceFiles.enabled: true and an include list instead of inputFiles.
  • Parameterize --column-names with a flow input so different callers validate different schemas.
  • Wrap this flow as a subflow and call it from every ingestion pipeline before loading.
  • Add an errors branch with a Slack or email task so producers hear about bad files immediately.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.