PostgreSQLMySQLSQL ServerSQLite

CHECK constraint failed

A row you tried to write violates a CHECK constraint's rule — the constraint is doing exactly what it was declared to do. The fix is deciding whether the data or the rule is wrong.

  • SQLite: CHECK constraint failed: amount >= 0
  • PostgreSQL: ERROR: new row for relation "orders" violates check constraint "orders_amount_check" DETAIL: Failing row contains (1, -50, ...).
  • MySQL (8.0.16+; earlier versions silently ignore CHECK): Check constraint 'orders_chk_1' is violated.
  • SQL Server: The INSERT statement conflicted with the CHECK constraint "CK_orders_amount". The conflict occurred in database "...", table "dbo.orders", column 'amount'.
SQL playground
Loading editor…
⌘/Ctrl + Enter

The cause

A CHECK constraint is a boolean expression attached to a column or table that every row has to satisfy. Unlike NOT NULL, UNIQUE, and foreign keys — which all enforce a specific, narrow shape — CHECK can express almost any rule: a range, a set of allowed values, a relationship between two columns in the same row. It's doing its job here; -50 genuinely fails amount >= 0.

Two legitimate responses, and they're opposites

The data is wrong — this is the common case, and the fix is upstream: find why your application produced a negative amount and fix that, the same way you would for a NOT NULL or foreign key violation.

The constraint is wrong, or was true when written and isn't anymore — requirements change. If negative amounts are now a legitimate case (a refund represented as a negative order, say), the constraint needs updating, not the data forced around it:

-- PostgreSQL / SQLite: drop and re-add
ALTER TABLE orders DROP CONSTRAINT orders_amount_check;
ALTER TABLE orders ADD CONSTRAINT orders_amount_check CHECK (amount >= -10000);

-- MySQL / SQL Server: broadly the same shape, constraint names required
ALTER TABLE orders DROP CONSTRAINT orders_amount_check;
ALTER TABLE orders ADD CONSTRAINT orders_amount_check CHECK (amount >= -10000);

A row that respects the (corrected) rule succeeds normally:

SQL playground
Loading editor…
⌘/Ctrl + Enter

Multi-column CHECK constraints fail the same way, with a less obvious cause

A CHECK isn't limited to one column — it can compare several, which means the failing value in the error message might not be the column that actually violates the rule:

SQL playground
Loading editor…
⌘/Ctrl + Enter

When a CHECK failure doesn't make sense looking only at the column named in the error, read the full constraint definition — the rule may span more than one column.

Change the CHECK expression above to something stricter or looser and see which rows start failing.Open the playground →