↑↓ select↵ open⌫ change scopeOpen full search

PG.CENTER connects PostgreSQL documentation, reference, and ecosystem knowledge. Maintained by Pigsty.

Wiki / SQLSTATE

23001 — restrict_violation

23001 is the specific RESTRICT violation condition. In the selected PostgreSQL 18.6 case, deleting a referenced parent row raised it with the child constraint and key in the diagnostic. PostgreSQL 10 reported the same tested operation through 23503, so version and server diagnostics must be recorded. A separate PostgreSQL 17.11 comparison also returned 23503 for this RESTRICT operation; it is not 23001 coverage.

English manual coverage begins with PostgreSQL 8.1. Source history and runtime observations have their own recorded version boundaries.

Reading PG 18·Select a recorded version

aliases
Unknown
class name
Integrity Constraint Violation
condition name
restrict_violation
lang
en
sqlstate
23001

Definition PG 18

23001 — restrict_violation

At a glance {#at-a-glance}

23001 is the specific RESTRICT violation condition. In the selected PostgreSQL 18.6 case, deleting a referenced parent row raised it with the child constraint and key in the diagnostic. PostgreSQL 10 reported the same tested operation through 23503, so version and server diagnostics must be recorded. A separate PostgreSQL 17.11 comparison also returned 23503 for this RESTRICT operation; it is not 23001 coverage.

Meaning {#meaning}

An ON DELETE RESTRICT or ON UPDATE RESTRICT action checks the referencing row immediately and refuses the parent change. This differs from NO ACTION: a DEFERRABLE NO ACTION constraint can postpone its check until the relevant commit, while RESTRICT is not deferrable. The source builds a dynamic primary/detail message from the parent table, foreign-key constraint, child table, and key visibility.

Diagnosis {#diagnosis}

Record the exact SQLSTATE and constraint_name, table_name, schema_name, and detail. Check the child rows before changing the parent. In an explicit transaction the failed delete leaves the connection INERROR; ROLLBACK is required before the repair transaction can delete the child and then the parent.

Response {#response}

Choose the action deliberately: remove or reassign dependent rows, change the parent operation, or redesign the FK action after reviewing its integrity meaning. Do not turn RESTRICT into a deferred NO ACTION merely to make a migration pass. The selected repair deletes the dependent row in a new BEGIN/COMMIT sequence and then deletes the parent.

Observed diagnostics {#messages}

18.6 (Homebrew) / latest:SQLSTATE 23001; primary update or delete on table "parents" violates RESTRICT setting of foreign key constraint "children_parent_id_fkey" on table "children"; DETAIL Key (id)=(1) is referenced from table "children".; after_error INERROR; after_rollback IDLE. 10.21 (Debian 10.21-1.pgdg90+1) / pg10:SQLSTATE 23503; primary update or delete on table "parents" violates foreign key constraint "children_parent_id_fkey" on table "children"; DETAIL Key (id)=(1) is still referenced from table "children".; after_error INERROR; after_rollback IDLE. 17.11 (pg17) / boundary:SQLSTATE 23503; primary update or delete on table "parents" violates foreign key constraint "children_parent_id_fkey" on table "children"; DETAIL Key (id)=(1) is still referenced from table "children".; after_error INERROR; after_rollback IDLE; final counts [0, 0]. This boundary case is not 23001 coverage.

Representative case {#case}

The runner reads these statements from verify/cases/23001/snippets.json (SHA-256 6086c1ce982afa5438bbcd29b86ec4cd0cbe0c76fa6152c1eb4a330a7706d5c8) and qualifies the temporary table names; the complete setup, assertions, and cleanup are in the case export.

-- create_parent
CREATE TABLE parents(id integer PRIMARY KEY);
-- create_child
CREATE TABLE children(id integer PRIMARY KEY, parent_id integer NOT NULL REFERENCES parents(id) ON DELETE RESTRICT);
-- seed_parent
INSERT INTO parents VALUES (1);
-- seed_child
INSERT INTO children VALUES (10, 1);
-- begin
BEGIN;
-- trigger
DELETE FROM parents WHERE id = 1;
-- rollback
ROLLBACK;
-- repair_begin
BEGIN;
-- repair_child
DELETE FROM children WHERE id = 10;
-- repair_parent
DELETE FROM parents WHERE id = 1;
-- commit
COMMIT;
-- verify
SELECT (SELECT count(*) FROM parents), (SELECT count(*) FROM children);

The SQLSTATE, diagnostic, transaction-state, and repair assertions for this excerpt are produced from the shared registry; structured evidence · case export.

Authored evidence IDs: identity, restrict-path, no-action-boundary, runtime, runtime.pg17-boundary. Selected base runtime records: runtime.23001-batch1-latest2-20260909.latest, runtime.23001-batch1-pg10b-20260909.pg10. Separate boundary record: runtime.23001-boundary-pg17-final-20260909.pg17.

Versions {#versions}

The locked catalogue observes the condition by 7.4 and in all listed formal snapshots. The selected base cases observe 23001 on 18.6 and 23503 on 10.21 for the same RESTRICT delete. A separate PG17.11 boundary comparison also returned 23503, with the same INERROR to IDLE recovery; it is retained as a comparison and does not establish a universal result for every PostgreSQL 11–17 minor release.

Related {#related}

Compare 23503 foreign-key violation, 23505 unique violation, and 23514 CHECK violation.

Sources {#sources}

Compare versions

SQLSTATE evidence and recorded runtime versions

cases · restrict_delete_referenced_parent
{
  "assertions": [
    "SQLSTATE is 23001",
    "The RESTRICT constraint and referencing table are identified",
    "Deleting the child first permits an explicit parent repair"
  ],
  "case_id": "restrict_delete_referenced_parent",
  "cleanup": "Drop the case schema with an owner connection.",
  "has_snippet": true,
  "position": 0,
  "preconditions": [
    "A child row references a parent through ON DELETE RESTRICT",
    "The parent delete is attempted while the child remains"
  ],
  "repair": "Resolve the dependent row according to business rules, then delete or retain the parent; changing RESTRICT to another action is a schema decision, not an error fix.",
  "trigger": "Delete the referenced parent row.",
  "versions": [
    "18"
  ]
}
claims · identity
{
  "claim_id": "identity",
  "limits": "The code is narrower than the general foreign-key violation code 23503.",
  "method": "Read the condition definition and macro.",
  "position": 0,
  "runtime": [],
  "sources": [
    "src.errcodes.18.6"
  ],
  "statement": "23001 is restrict_violation, a specific Class 23 condition."
}
claims · restrict-path
{
  "claim_id": "restrict-path",
  "limits": "The exact DETAIL depends on privileges and key values; do not treat one rendered DETAIL as a static format string.",
  "method": "Trace the fixed ri_ReportViolation call and compare the documented action timing.",
  "position": 1,
  "runtime": [],
  "sources": [
    "src.ri_triggers.18.6",
    "src.calls.REL_18_6",
    "doc.ddl-constraints.18.6"
  ],
  "statement": "The RI trigger reports 23001 when an immediate ON DELETE or ON UPDATE RESTRICT action finds a referencing row."
}
claims · no-action-boundary
{
  "claim_id": "no-action-boundary",
  "limits": "The PG10 result is a version/path boundary, not evidence that the user operation succeeded.",
  "method": "Read action semantics and the two selected runs.",
  "position": 2,
  "runtime": [],
  "sources": [
    "src.ri_triggers.18.6",
    "doc.ddl-constraints.18.6",
    "runtime.23001-batch1-pg10b-20260909.pg10"
  ],
  "statement": "RESTRICT is checked immediately and is not deferrable; NO ACTION can be deferred when the constraint is declared DEFERRABLE, and PostgreSQL 10 uses the general 23503 path for the tested RESTRICT delete."
}
claims · runtime
{
  "claim_id": "runtime",
  "limits": "Only the PG18 result is an observed runtime for code 23001; the PG10 case is explicitly not_applicable for that code.",
  "method": "Compare summaries and raw diagnostics with the shared registry.",
  "position": 3,
  "runtime": [],
  "sources": [
    "runtime.23001-batch1-latest2-20260909.latest",
    "runtime.23001-batch1-pg10b-20260909.pg10"
  ],
  "statement": "The selected PG18 run returned 23001, entered INERROR, recovered after ROLLBACK, and committed deletion after removing the dependent row; PG10 returned 23503 for the same mechanism."
}
claims · runtime.pg17-boundary
{
  "claim_id": "runtime.pg17-boundary",
  "limits": "This is one PG17.11 comparison point and is not a universal claim for every PostgreSQL 11–17 minor release. It is not an observed 23001 runtime.",
  "method": "Read the PG17 boundary summary for the exact primary/detail, SQLSTATE, transaction statuses, and final counts.",
  "position": 4,
  "runtime": [],
  "sources": [
    "restrict-path",
    "runtime.23001-boundary-pg17-final-20260909.pg17"
  ],
  "statement": "On the fixed PG17.11 boundary case, the same referenced-parent ON DELETE RESTRICT operation returned the general foreign_key_violation 23503 rather than dedicated 23001; the failed transaction moved from INERROR to IDLE after ROLLBACK and cleanup assertions passed."
}
messages · restrict
{
  "limits": "The privilege-aware branch can instead emit the source detail template without key values.",
  "message_id": "restrict",
  "path": "",
  "position": 0,
  "raw": {
    "detail_template": "Key (%s)=(%s) is referenced from table \"%s\".",
    "id": "restrict",
    "limits": "The privilege-aware branch can instead emit the source detail template without key values.",
    "primary_template": "update or delete on table \"%s\" violates RESTRICT setting of foreign key constraint \"%s\" on table \"%s\"",
    "severity_source": "ERROR",
    "sources": [
      "src.ri_triggers.18.6"
    ],
    "sqlstate": "23001"
  },
  "severity": "ERROR",
  "sources": [
    "src.ri_triggers.18.6"
  ],
  "templates": [
    {
      "kind": "primary",
      "literal": "update or delete on table \" \" violates RESTRICT setting of foreign key constraint \" \" on table \" \"",
      "position": 0,
      "role": "",
      "template": "update or delete on table \"%s\" violates RESTRICT setting of foreign key constraint \"%s\" on table \"%s\""
    },
    {
      "kind": "detail",
      "literal": "Key ( )=( ) is referenced from table \" \".",
      "position": 1,
      "role": "",
      "template": "Key (%s)=(%s) is referenced from table \"%s\"."
    }
  ]
}
runtimes · runtime.23001-batch1-latest2-20260909.latest · 18.6 (Homebrew) · passed
{
  "cases": [
    "restrict_delete_referenced_parent"
  ],
  "limits": "",
  "position": 0,
  "raw": {
    "case_manifest": {
      "path": "verify/cases/23001/cases.json",
      "sha256": "eca00a2f8f981d7f1ccf77e661b52690631bfedc399003f73ccc43de6a06a1bc"
    },
    "cases": [
      "restrict_delete_referenced_parent"
    ],
    "id": "runtime.23001-batch1-latest2-20260909.latest",
    "observed": {
      "after_error": "INERROR",
      "after_rollback": "IDLE",
      "detail": "Key (id)=(1) is referenced from table \"children\".",
      "final_counts": [
        0,
        0
      ],
      "primary": "update or delete on table \"parents\" violates RESTRICT setting of foreign key constraint \"children_parent_id_fkey\" on table \"children\"",
      "sqlstate": "23001"
    },
    "raw": "verify/results/23001-batch1-latest2-20260909/latest/raw.jsonl",
    "raw_sha256": "4f5c32e84c543203a9ebb757c2a3567b2441bd2f7aaf6f0ec0daa3d187474ea9",
    "run_id": "23001-batch1-latest2-20260909",
    "server_version": "18.6 (Homebrew)",
    "server_version_num": 180006,
    "snippet_registry": {
      "path": "verify/cases/23001/snippets.json",
      "sha256": "6086c1ce982afa5438bbcd29b86ec4cd0cbe0c76fa6152c1eb4a330a7706d5c8"
    },
    "status": "passed",
    "summary": "verify/results/23001-batch1-latest2-20260909/latest/summary.json",
    "summary_sha256": "e38c907a737001707b5409de058e959f9da3711d7ab2c72c318d37f043351fc1",
    "target": "latest"
  },
  "run_id": "23001-batch1-latest2-20260909",
  "runtime_id": "runtime.23001-batch1-latest2-20260909.latest",
  "server_version": "18.6 (Homebrew)",
  "status": "passed",
  "target": "latest"
}
runtimes · runtime.23001-batch1-pg10b-20260909.pg10 · 10.21 (Debian 10.21-1.pgdg90+1) · not_applicable
{
  "cases": [
    "restrict_delete_referenced_parent"
  ],
  "limits": "",
  "position": 1,
  "raw": {
    "case_manifest": {
      "path": "verify/cases/23001/cases.json",
      "sha256": "eca00a2f8f981d7f1ccf77e661b52690631bfedc399003f73ccc43de6a06a1bc"
    },
    "cases": [
      "restrict_delete_referenced_parent"
    ],
    "id": "runtime.23001-batch1-pg10b-20260909.pg10",
    "observed": {
      "after_error": "INERROR",
      "after_rollback": "IDLE",
      "detail": "Key (id)=(1) is still referenced from table \"children\".",
      "final_counts": [
        0,
        0
      ],
      "primary": "update or delete on table \"parents\" violates foreign key constraint \"children_parent_id_fkey\" on table \"children\"",
      "sqlstate": "23503"
    },
    "raw": "verify/results/23001-batch1-pg10b-20260909/pg10/raw.jsonl",
    "raw_sha256": "92928af8522d2224aaaf21e8eb7a2d974e433a80d6f2b1bf33296588738d21b7",
    "reason": "PostgreSQL 10 reports this RESTRICT delete through the general foreign-key violation path 23503; the dedicated 23001 path is observed on PostgreSQL 18.",
    "run_id": "23001-batch1-pg10b-20260909",
    "server_version": "10.21 (Debian 10.21-1.pgdg90+1)",
    "server_version_num": 100021,
    "snippet_registry": {
      "path": "verify/cases/23001/snippets.json",
      "sha256": "6086c1ce982afa5438bbcd29b86ec4cd0cbe0c76fa6152c1eb4a330a7706d5c8"
    },
    "status": "not_applicable",
    "summary": "verify/results/23001-batch1-pg10b-20260909/pg10/summary.json",
    "summary_sha256": "ab114f4849fce773011f9069f644fd10d73abb66329ae931160fc8ecea295026",
    "target": "pg10"
  },
  "run_id": "23001-batch1-pg10b-20260909",
  "runtime_id": "runtime.23001-batch1-pg10b-20260909.pg10",
  "server_version": "10.21 (Debian 10.21-1.pgdg90+1)",
  "status": "not_applicable",
  "target": "pg10"
}
runtimes · runtime.23001-boundary-pg17-final-20260909.pg17 · 17.11 (Debian 17.11-1.pgdg13+2) · not_applicable
{
  "cases": [
    "restrict_delete_referenced_parent"
  ],
  "limits": "",
  "position": 2,
  "raw": {
    "case_manifest": {
      "path": "verify/cases/23001/cases.json",
      "sha256": "eca00a2f8f981d7f1ccf77e661b52690631bfedc399003f73ccc43de6a06a1bc"
    },
    "case_status": "not_applicable",
    "cases": [
      "restrict_delete_referenced_parent"
    ],
    "id": "runtime.23001-boundary-pg17-final-20260909.pg17",
    "observed": {
      "after_error": "INERROR",
      "after_rollback": "IDLE",
      "constraint_name": "children_parent_id_fkey",
      "detail": "Key (id)=(1) is still referenced from table \"children\".",
      "expected_sqlstate": "23503",
      "final_counts": [
        0,
        0
      ],
      "natural_23001_observed": false,
      "primary": "update or delete on table \"parents\" violates foreign key constraint \"children_parent_id_fkey\" on table \"children\"",
      "severity": "ERROR",
      "sqlstate": "23503"
    },
    "raw": "verify/results/23001-boundary-pg17-final-20260909/pg17/raw.jsonl",
    "raw_sha256": "2929c03723d90f76192e3d3ffc2f4f5a8a643f9a5f0eb898f7245f3cf6439c87",
    "reason": "The bounded PG17.11 RESTRICT delete uses the general 23503 path; the dedicated 23001 path is not applicable on this target.",
    "run_id": "23001-boundary-pg17-final-20260909",
    "selection_status": "selected_boundary_comparison",
    "server_version": "17.11 (Debian 17.11-1.pgdg13+2)",
    "server_version_num": 170011,
    "snippet_registry": {
      "path": "verify/cases/23001/snippets.json",
      "sha256": "6086c1ce982afa5438bbcd29b86ec4cd0cbe0c76fa6152c1eb4a330a7706d5c8"
    },
    "status": "not_applicable",
    "summary": "verify/results/23001-boundary-pg17-final-20260909/pg17/summary.json",
    "summary_sha256": "54174fb5450b9bade0e1788e288be5bf24792f161e71e9299b7095e1f40333e6",
    "target": "pg17",
    "target_status": "passed"
  },
  "run_id": "23001-boundary-pg17-final-20260909",
  "runtime_id": "runtime.23001-boundary-pg17-final-20260909.pg17",
  "server_version": "17.11 (Debian 17.11-1.pgdg13+2)",
  "status": "not_applicable",
  "target": "pg17"
}
sources · src.errcodes.18.6
{
  "commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
  "docs_url": "",
  "kind": "upstream_source",
  "location": "",
  "path": "src/backend/utils/errcodes.txt",
  "position": 0,
  "sha256": "6e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba",
  "source_id": "src.errcodes.18.6",
  "tag": "REL_18_6",
  "url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/errcodes.txt"
}
sources · src.calls.REL_18_6
{
  "commit": "",
  "docs_url": "",
  "kind": "local_artifact",
  "location": "",
  "path": "raw/calls/REL_18_6.jsonl",
  "position": 1,
  "sha256": "9ee8a0e81d8f0825c5c1ae45583439859a26e602bdd4ce2f2a62aa278867ccbf",
  "source_id": "src.calls.REL_18_6",
  "tag": "",
  "url": ""
}
sources · src.ri_triggers.18.6
{
  "commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
  "docs_url": "",
  "kind": "upstream_source",
  "location": "",
  "path": "src/backend/utils/adt/ri_triggers.c",
  "position": 2,
  "sha256": "a3fed49fbda88fe0fe5bcf35eb019fced28596ae4046233f2acb2eb9f90ab1da",
  "source_id": "src.ri_triggers.18.6",
  "tag": "REL_18_6",
  "url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/adt/ri_triggers.c#L2785-L2797"
}
sources · doc.ddl-constraints.18.6
{
  "commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
  "docs_url": "https://www.postgresql.org/docs/18/ddl-constraints.html#DDL-CONSTRAINTS-FK",
  "kind": "upstream_source",
  "location": "",
  "path": "doc/src/sgml/ddl.sgml",
  "position": 3,
  "sha256": "ce1919d9236f2e71672660e1a347146472e966e4d19b77fde5ae345dd1db6ec7",
  "source_id": "doc.ddl-constraints.18.6",
  "tag": "REL_18_6",
  "url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/doc/src/sgml/ddl.sgml"
}

Source references

Full definition and evidence JSON

Definition sources

center · PostgreSQL 18 · english-manuals:f22256a96e7c13b90f1206172fb2665991d5fed5fad68c6adebcb48d3a97e19e

Text language: en · english-manuals:f22256a96e7c13b90f1206172fb2665991d5fed5fad68c6adebcb48d3a97e19e