# Validation

> What the engine checks on every write, how it refuses a bad value, and how to try a write first.

The engine checks every write against its table before it changes anything: required values, types, ranges, enums, links, unique values and CHECK constraints. When one check fails, it refuses the whole write and writes nothing. The refusal names the note, the column or rule, the values the engine accepts, and how to fix the call.

People, programs and agents go through the same checks. Hand edits are checked too, but never refused: [Hand edits](https://datanotes.dev/guides/data-quality/hand-edits/) shows what happens to them.

## See how the engine refuses bad values

The engine checks every write against the columns. If one value is wrong, it writes nothing, and the answer names the column and the reason. For an enum, the answer also lists the allowed values.

**`insert_row`**

```json
{
  "table": "film",
  "values": { "title": "Battleship Potemkin", "minutes": 0, "status": "finished" }
}
```

Refused:

```text
insert_row refused — nothing was written:
invalid datanotes/main/public/film/Battleship Potemkin.md: minutes must be >= 1
invalid datanotes/main/public/film/Battleship Potemkin.md: status must be one of: to watch; watched
Hint: Give a value inside the column's range (the message names the bound); describe_table shows its min and max. Use one of the allowed values listed in the message, written exactly; describe_table shows what each one means. To add a value, alter_column the enum. Then call insert_row again (dry_run: true checks without writing).
Docs: https://datanotes.dev/guides/database-objects/tables.md#describe-a-table-before-writing-to-it (offline: read_docs("guides/database-objects/tables#describe-a-table-before-writing-to-it"))
```

A unique column refuses a second row with the same value:

**`insert_row`**

```json
{ "table": "film", "values": { "title": "Metropolis" } }
```

Refused:

```text
insert_row refused — nothing was written:
invalid datanotes/main/public/film/Metropolis-2.md: title must be unique (also used by datanotes/main/public/film/Metropolis.md)
Hint: Another row already has this value: choose another one, or update that row instead (select_rows finds it). Then call insert_row again (dry_run: true checks without writing).
Docs: https://datanotes.dev/guides/read-and-write/write-rows.md#update-one-row (offline: read_docs("guides/read-and-write/write-rows#update-one-row"))
```

## Try a write first with `dry_run`

Every write accepts `dry_run: true`. The engine checks the write and reports what it would do, but writes nothing.

**`insert_row`**

```json
{
  "table": "film",
  "values": { "title": "Battleship Potemkin", "year": 1925, "minutes": 75 },
  "dry_run": true
}
```

Answer:

```json
{
  "ok": true,
  "op": "insert_row",
  "dry_run": true,
  "planned_creates": ["datanotes/main/public/film/Battleship Potemkin.md"]
}
```

The table still has one film:

**`select_rows`**

```json
{ "table": "film", "columns": ["title"] }
```

Answer:

```json
{
  "table": "main.public.film",
  "total": 1,
  "rows": [{ "path": "datanotes/main/public/film/Metropolis.md", "title": "Metropolis" }]
}
```
