> For the complete documentation index, see [llms.txt](https://v2.dataos.info/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://v2.dataos.info/build/stage-2-productize/validate-and-test-locally.md).

# Validate locally

Before deploying to production, validate and test your entire project locally. This catches SQL errors, dependency issues, schema mismatches, and assertion failures in an isolated environment where they can be fixed safely.

***

## The validation cycle

```
vulcan info          --> check project structure and connection
vulcan test          --> unit tests against mock data
vulcan evaluate      --> inspect model output with row limits
vulcan plan          --> full plan: detect changes, run audits
```

Run these in order. Fix each layer before moving to the next.

***

## Step 1: Check project structure

`vulcan info` validates your `config.yaml`, project structure, and connection settings:

```bash
vulcan info
```

A clean output confirms:

* `config.yaml` is valid and all required fields are set.
* The warehouse connection is reachable.
* The model directory structure is recognized.

Fix any errors reported before running the plan.

***

## Step 2: Run unit tests

`vulcan test` runs all YAML tests in `tests/` against mock data. No warehouse access is required:

```bash
# Run all tests
vulcan test

# Run tests for a specific model
vulcan test --select silver.fct_daily_sales

# Run a specific test file
vulcan test tests/test_fct_daily_sales.yaml
```

In `orders-analytics`, running `vulcan test` executes both tests:

```
test_fct_daily_sales_excludes_cancelled_orders          PASS
test_rfm_customer_segmentation_champion                 PASS
```

A failing test shows a diff between expected and actual output. Fix the model logic or the test expectations, then re-run.

***

## Step 3: Inspect model output

`vulcan evaluate` executes a model against the warehouse and returns a preview of the output. Use it to inspect row counts, check column values, and verify the query produces what you expect:

```bash
# Preview the first 10 rows of the daily sales fact table
vulcan evaluate silver.fct_daily_sales --limit 10

# Preview the RFM segmentation output
vulcan evaluate gold.rfm_customer_segmentation --limit 10
```

Check for:

* Are there rows? (empty output often means a wrong filter or a missing upstream model)
* Are measure values reasonable? (no negative revenue, shipment rates between 0 and 1)
* Are dimensions populated? (no unexpected nulls in region\_name, category, or customer\_id)
* Does the row count match your grain expectations?

***

## Step 4: Run the plan

`vulcan plan` detects all changes in your project, generates a deployment plan, and runs all attached assertions against the new data:

```bash
vulcan plan
```

**What the plan output shows for orders-analytics:**

```
Plan: 13 models to evaluate, 1 seed to load

  bronze.order_status_lookup  (seed)    [new]
  bronze.orders               (full)    [new]
  bronze.order_items          (full)    [new]
  bronze.customers            (full)    [new]
  ...
  silver.fct_daily_sales      (full)    [new]
  silver.dim_customer_profile (full)    [new]
  gold.rfm_customer_segmentation (full) [new]
  gold.sales_funnel_analysis  (full)    [new]

Audits: 15 passed, 0 failed
```

If assertions fail:

1. Read the exact query Vulcan ran (add `--verbose` to see it).
2. Identify the failing rows: what data triggered the check?
3. Fix either the source data or the model logic.
4. Re-run `vulcan plan`.

***

## Step 5: Debug SQL rendering

Inspect the exact SQL Vulcan generates for a model. This is useful when macros produce unexpected results or a model output looks wrong:

```bash
vulcan render silver.fct_daily_sales
```

The rendered SQL shows exactly what Vulcan will execute, with all macro substitutions applied. For `orders-analytics`, this lets you verify that `@revenue_order_filter(o.order_status)` expanded to `o.order_status <> 'Cancelled'` and `@safe_ratio(...)` expanded to the correct `ROUND(COALESCE(... / NULLIF(..., 0), 0), N)` expression.

***

## Step 6: Check model graph

View the dependency graph to confirm Vulcan has detected all dependencies correctly:

```bash
vulcan export dag dag.html
```

Open `dag.html` in a browser. In `orders-analytics`, you should see the bronze models at the root, silver models depending on bronze, gold models depending on silver, and semantic models depending on the gold and silver models. If a model is missing from the graph, check that its `FROM` clause references the correct fully-qualified model name.

***

## Step 7: Run assertions manually

Run all assertions independently of a plan to check data quality on the current state:

```bash
vulcan audit

# With verbose output to see failing rows
vulcan audit --verbose
```

***

## Common issues and fixes

| Issue                        | Likely cause                                    | Fix                                                                           |
| ---------------------------- | ----------------------------------------------- | ----------------------------------------------------------------------------- |
| Empty model output           | Missing upstream model or wrong filter          | Run the plan; check dependency ordering; verify filter logic                  |
| `Relation does not exist`    | Upstream model not materialized yet             | Run the plan first; check that the model name in the `FROM` clause is correct |
| `Column not found`           | Name mismatch between SELECT and MODEL block    | Match column names exactly in the DDL and the SELECT                          |
| Assertion fails unexpectedly | Data variance exceeds what the assertion allows | Run `vulcan audit --verbose` to see the exact failing rows                    |
| `Duplicate model name`       | Model already exists from a previous plan       | Drop the existing table or use `--restate-model`                              |
| YAML parse error             | Bad indentation in test or DQ file              | Check indentation levels; YAML requires consistent spacing                    |
| Macro expansion is wrong     | Macro arguments are in the wrong order          | Check the macro signature in `macros/orders_helpers.py`                       |

***

## Next step

Once the plan passes cleanly, proceed to [Stage 3: Publish](/build/stage-3-publish/overview.md) to deploy to production and share the Data Product.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://v2.dataos.info/build/stage-2-productize/validate-and-test-locally.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
