---
updatedAt: 2026-09-22T00:40:21.000Z
agentTools:
  projectIndex: https://docs.getmontecarlo.com/llms.txt
---

# Validation Monitors

Validation monitors help to identify rows in your tables with bad data ("invalid rows"). They make it easy for users with limited or no SQL knowledge to set up alert conditions on specific fields or a combination of fields. For example, to validate that strings are formatted correctly, timestamps are not in the future, and numerical values are not negative.

<Callout icon="📘" theme="info">
  ### To configure validation monitors as code, see the [Validation Monitor MaC reference](../../../Developer%20Tools/monitors-as-code/monitor-types/validation-monitors/validation.md).
</Callout>

Users can choose from a rich library of operators and templated alert conditions, or create their own using custom SQL. See [Available Conditions](https://docs.getmontecarlo.com/docs/available-conditions) for a full list of operators and templated conditions.

# Creating Validation Monitors

Validation monitors can be created from the [Create Monitor](https://getmontecarlo.com/monitors/create) page or Assets page. Configuration steps include:

## Choose Data

Users have two options to choose data from.

1. Select a table or view:

   <Image src="https://files.readme.io/5973932-Screenshot_2024-07-01_at_4.12.18_AM.png" align="center" />

2. Write a SQL query:

   * Select warehouse
   * Write a SQL query and click `Test`  to validate the SQL.

   <Image src="https://files.readme.io/f89ffee-Screenshot_2024-07-01_at_4.20.47_AM.png" align="center" />

   `Test` will help users preview all the fields the SQL query returns.

   <Image src="https://files.readme.io/695ac44-Screenshot_2024-07-01_at_4.23.01_AM.png" alt="Screenshot 2024-07-01 at 4.23.01 AM.png" align="center" caption="Example: SQL query can be something like `select * from table_name`" />

## Define alert conditions

Users define alert conditions by adding their own conditions or by getting recommended conditions from the Monitoring agent.

There are 3 types of alert conditions that users can setup when adding their own conditions:

1. **Predefined Conditions**

   Predefined conditions start with `is` operator. Conditions are specific to the data type of field.

   <Image src="https://files.readme.io/9ee7235-Screenshot_2024-07-01_at_4.29.41_AM.png" align="center" />

   <Image src="https://files.readme.io/b0d15fc-Screenshot_2024-07-01_at_4.29.54_AM.png" align="center" />

2. **Conditions with values set by user**

   These conditions have standard operators for data types like

   * **numerics**: equal, greater\_than, greater\_than\_equal, less\_than, less\_than\_equal, in\_set, not\_in\_set
   * **date, time**: equal, greater\_than, greater\_than\_equal, less\_than, less\_than\_equal
   * **string**: equal, contains, starts\_with, ends\_with, matches\_regex, in\_set, not\_in\_set
   * **boolean**: equal

   The user needs to provide a field and a value for these conditions.

   <Image src="https://files.readme.io/316691a-Screenshot_2024-07-01_at_4.33.53_AM.png" align="center" />

   <Image src="https://files.readme.io/681851a-Screenshot_2024-07-01_at_4.34.26_AM.png" align="center" />

   <Image src="https://files.readme.io/5b6e869-Screenshot_2024-07-01_at_4.34.56_AM.png" align="center" />

3. **SQL expressions**

   For greater flexibility users can also pass in a SQL expression as a condition and test it as well.

   <Image src="https://files.readme.io/77eb1dc-Screenshot_2024-07-01_at_4.41.16_AM.png" align="center" />

Users can use all of these above conditions to create more complex alert conditions to alert on.

For example: alert conditions combinations like `test_string = ‘qwerty’ AND (test_number > 100 OR test_boolean = True) AND test_date > July 12, 2024`  will look like this:

<Image src="https://files.readme.io/99e0296-Screenshot_2024-07-01_at_4.43.55_AM.png" align="center" />

### Monitoring agent recommendations

The Monitoring agent recommends alert conditions by sampling data of up to 10k rows based on the user-selected time field and time range. Learn more about [Monitoring agent recommendations](https://docs.getmontecarlo.com/docs/using-the-data-profiler#monitoring-agent-recommendations).

## Set Threshold

Choose how many breached rows trigger an alert:

* **Any row** (default): alert when one or more rows meet the alert conditions.
* **Percentage of total rows**: alert only when breached rows exceed a defined percentage of total rows. Useful when small numbers of failures are expected and only a material breach rate should fire an alert.

When **Percentage of total rows** is selected, configure an operator (`greater than`, `greater than or equal to`, `equal to`) and a percentage value. The baseline (denominator) is determined automatically from the [Choose Data](#1-choose-data) step:

* **Table or view selected**: the row count of the selected table at run time, after any filters and time range set on the monitor. With none set, this is the full table.
* **SQL query as data source**: row count returned by the source query at run time.

## Define Schedule

Select when the monitor should run. There are several options:

* **On a schedule**: Input a regular, periodic schedule. Options for handling daylight savings are available in the advanced dropdown.
* **CRON based**: Input a cron expression to run on a schedule specified by the cron. Options for handling daylight savings are available in the advanced dropdown.
* **By trigger**:
  * **Manual trigger**: Select this option when you want to manually trigger using the `Run` button on the monitor description page.
  * **When a table is updated**: The monitor will run when Monte Carlo sees that the table has been updated. This logic uses the history of table updates that Monte Carlo gets through its hourly collection of metadata. The run will occur up to 30 minutes after an update, but not more than once every 2 hours. Use the **Run periodically if trigger doesn't fire** toggle to control whether the monitor also runs on a fallback schedule (every 48 hours by default) when no table update is detected.
  * **When a job or task completes**: The monitor will run when Monte Carlo detects a successful job or task execution, but not more frequently than every 2 hours. Use the **Run periodically if trigger doesn't fire** toggle to control whether the monitor also runs on a fallback schedule (every 48 hours by default) when no job or task executions are detected.

<Image src="https://files.readme.io/b00e72e-Screenshot_2024-07-01_at_3.40.28_PM.png" align="center" />

## Send notifications

Select which audiences should receive notifications when an anomaly is detected.

Additional settings exist for setting the description of the monitor which will be set as the header for notifications sent to notification channels, also pre-setting a priority on any incidents generated by the monitor.

See here for more information on [Audiences and Notifications](https://docs.getmontecarlo.com/docs/notifications-v2). Learn more about setting [Monitor tags](https://docs.getmontecarlo.com/docs/monitor-tags).

### Notes

Text in the **Notes** section will be included directly in notifications. The "Show notes tips" dropdown includes details on how to @mention an individual or team if you are sending notifications to Slack.

Notes support rich-text formatting, including bold, italic, underline, strike-through, lists, links, and code blocks. Rich-text channels display these styles, while text-only channels show a plain-text equivalent.

Monitor properties can be dynamically inserted into Notes through variables. Supported variables include `Created by`, `Last updated at`,` Last updated by`, `Priority`, `Tags` and—for Validation and Custom SQL monitors—`Query Result`.

## Measuring evaluated rows

Validation monitors report both the invalid rows and the total population they came from — for example, 1,000 invalid rows out of 40,000 evaluated.

<Accordion title="Prerequisite: one-time enablement" icon="fa-lock">
  A validation monitor returns only the invalid rows, so counting the total means a second query against your warehouse on each run.

  To opt-in, an account owner or editor can run the following in the [API Explorer](https://getmontecarlo.com/graphiql) or any API client:

  ```graphql
  mutation {
    toggleAccountFeature(feature: "record_evaluated_row_counts", isEnabled: true) {
      success
    }
  }
  ```

  Enabling starts recording total rows evaluated on every validation monitor in the account, on each monitor's next run. Custom SQL monitors record once a baseline query is defined.
</Accordion>

The total population is derived from the **Choose data** step, after any filters and time window are applied — so it matches the scope your alert conditions apply to, not the whole table. It's the same total the **Percentage of total rows** threshold uses as its denominator.

When enabled, the evaluated row count is recorded on every run, clean or breaching — in the monitor's **Results** tab, within **Alerts**, and via the [getJobExecutions](https://apidocs.getmontecarlo.com/#query-getJobExecutions) API, where each run carries `runEvaluatedRowCount` alongside `runBreachedRowCount`, for custom aggregations and reporting.

# Alerts and Notifications

Validation monitors generate an **alert** whenever at least one row breaches the defined alert condition(s).

Alerts from Validation monitors include the following details:

* Number of rows that breached the alert conditions
* List of the invalid rows
* Historical graph of current and previous breaches

<Image src="https://files.readme.io/7b585fa-Screenshot_2024-07-01_at_4.53.51_AM.png" align="center" />

<br />

Alert **notifications** are sent to your configured audiences and include:

* Description of the condition that was violated
* Number of rows that breached the alert condition
* When the last breach occurred

<Image src="https://files.readme.io/087bf95-Screenshot_2024-07-01_at_5.17.00_AM.png" align="center" />

# Examples

### Validate that field values are not null

In this case we need to alert if test\_field is null:

<Image src="https://files.readme.io/17b3fd7-Screenshot_2024-07-03_at_1.04.04_PM.png" align="center" />

### Validate that numerical values are not negative

In this case we need to alert if `numeric_field is negative`:

<Image src="https://files.readme.io/08eb1fe-Screenshot_2024-07-02_at_3.49.36_AM.png" align="center" />

### Validate that strings are formatted correctly

In this case we need to alert if `string_field` is not a specified format, say, uuid - `string_field is not UUID`:

<Image src="https://files.readme.io/22a8ef9-Screenshot_2024-07-02_at_3.43.34_AM.png" align="center" />

Or alert if  `us_phone_field is not US phone number`:

<Image src="https://files.readme.io/5850645-Screenshot_2024-07-02_at_3.45.30_AM.png" align="center" />

See [here](https://docs.getmontecarlo.com/docs/validation-monitors#available-conditions) for more formats.

### Validate that timestamps are not in the future

In this case we need to alert if `timestamp_field is not in the future`:

# Legacy monitors now included in Validation Monitors

Up until September 2024, **Cardinality Rules** and **Referential Integrity Rules** were options on the Monitor Menu in Monte Carlo. These were purpose-built monitor creation experiences that produced a SQL Rule. These were for use cases like:

* Alert me if any of the values in \[field] are not included in set \[value1, value2, value3, etc]
* Alert me if any of the values in \[field] are not present in \[table > field]

These were made redundant by Validations, so the experiences to create new ones were removed from the UI. Existing Cardinality Rules and Referential Integrity Rules continue to function.

In Validation Monitors, the recommended way to address these use cases in now with the `Is in set` and `Is not in set` operators, which allow a user to define a set:

* **From a list**: manually enter the values
* **From a field**: select a table and field, and the set with be populated with the distinct values in that field. The selected field will be referenced each time the monitor is run, so the set values may change.
* **From a query**: write SQL to define the values in the set. The query will run each time the monitor is run, so the set values may change.

<Image src="https://files.readme.io/e4bdcd02df3fbbeafc628f9baf4c0aad133ce812fc452108ac802ec6692f002e-Pasted_Image_9_12_24__12_39_PM.png" alt="`Is in set` and `Is not in set` operators in Validation Monitors" align="center" caption="`Is in set` and `Is not in set` operators in Validation Monitors" />

<br />

<Image src="https://files.readme.io/896bf409710bbfed94bd9fa64420ed8a47593c0050783dda051e3f580703f0bc-Pasted_Image_9_12_24__12_41_PM.png" alt="Options to define a set from a list, from a field, or from a query" align="center" width="550px" caption="Options to define a set from a list, from a field, or from a query" />