SQLSTATE 23001Severity mediumLab verified

Incident brief

RESTRICT foreign-key violation

Deleting or updating a parent row still referenced by a child fails when the foreign key is ON DELETE/UPDATE RESTRICT. On PostgreSQL 18+, that path raises SQLSTATE 23001 (restrict_violation) with a RESTRICT-specific message. On PostgreSQL 14-17 the same RESTRICT action still blocks the change but reports SQLSTATE 23503 (foreign_key_violation), same practical fix, different errcode. Clear or reassign the child rows first.

What lands in your log

ERROR: update or delete on table "parent_r" violates RESTRICT setting of foreign key constraint "child_r_pid_fkey" on table "child_r"

Reproduced on PostgreSQL 18.6 (primary); cross-checked 16.14Verified 2026-08-15 (Docker lab, PostgreSQL 18.6 + 16.14)Verified against PostgreSQL 18.6 (23001) and 16.14 (23503 for same RESTRICT DDL) in isolated labs

In 10 seconds

What triggers it
Create a parent/child foreign key with ON DELETE RESTRICT and insert a referenced parent row plus a child that references it.
Fix
Delete or reassign the referencing child rows before deleting the parent.
Proof
Reproduced on PostgreSQL 18.6 (primary); cross-checked 16.14 → On PG 18.6, DELETE parent under ON DELETE RESTRICT raises SQLSTATE 23001 with RESTRICT-specific message text. On PG 16.14 the identical DDL/DML raises SQLSTATE 23503 instead, still blocked, different code.

Fix

What to do right now

Application-level steps for this error.

  • Delete or reassign the referencing child rows before deleting the parent.
  • Or, if cascade semantics are intended, define the foreign key ON DELETE CASCADE deliberately.
  • Version note: only PostgreSQL 18+ distinguishes RESTRICT as SQLSTATE 23001; on 14-17 match on the FK violation message/constraint name or treat 23503 the same way operationally.
Fix SQL
-- Remove the referencing child rows first.
DELETE FROM child_r WHERE pid = 1;
DELETE FROM parent_r WHERE id = 1;

Runbook to fix this

The runbook for this incident

Full step-by-step fixes for the condition behind this error: the diagnosis, the exact SQL, and output captured in the lab.

Verification

PG 18.6 (primary); cross-checked 16.14
Last verified
2026-08-15 (Docker lab, PostgreSQL 18.6 + 16.14)
Verification scope
Verified against PostgreSQL 18.6 (23001) and 16.14 (23503 for same RESTRICT DDL) in isolated labs
Audit status
reviewed
ShareLinkedInX

Went further?

Pro unlocks the second lab proof

Free page stops the bleeding. Pro adds the operational test, SQLSTATE audit, and deeper evidence, same error, more certainty.

FollowSubstackLinkedInnew errors · lab notes · hiring loops