Independent technical referenceOfficial site
  • Software and digital services
  • Databases

23503

PostgreSQL 23503 foreign_key_violation: broken table reference

Verified with sources2 sourcesReviewed Oct 19, 2026
Technician coming? See the 2 steps they must show you
Trace

Risk level

Medium

Proceed carefully and stop if the check is unclear.

Urgency

Medium

Quick answer

PostgreSQL 23503 (foreign_key_violation) means an INSERT, UPDATE, or DELETE broke referential integrity between a referencing table and a referenced table. Check the Constraint, Table, and Detail error fields to see whether a parent key is missing or child rows still depend on the parent.

Safety first

Stop and check this first

  • Never switch a foreign key to `ON DELETE CASCADE` or mark it `NOT ENFORCED` without reviewing what the tables represent; Section 5.5.5 warns that cascading a deletion across independent objects (such as deleting order history when a product is removed) can silently destroy critical records.
  • Do not attempt to post raw `Detail` messages containing customer identifiers or keys to external issue trackers without redacting sensitive values first.

Safe checks you can perform

  • Inspect Constraint, Table, and Detail fields to determine the failure direction
  • Check pg_constraint for referenced table, referential actions, and deferrability
  • Verify parent-before-child ordering or deferred constraint mode inside the transaction

Leave these tasks to a qualified professional

  • Do not attempt this professional task: Enforce parent-first writes or use DEFERRABLE INITIALLY DEFERRED for cyclic inserts
  • Do not attempt this professional task: Explicitly handle dependent child rows and index referencing columns when appropriate

What a technician must be able to justify

Technician visit

These are the steps they must carry out and show you. Tick them as they work: if steps are skipped, do not accept a part swap.

These are not instructions for opening or handling the equipment yourself. They are the checks that should support a technical conclusion.

  1. Enforce parent-first writes or use DEFERRABLE INITIALLY DEFERRED for cyclic inserts

    What they doHave your developer order transaction writes so the referenced parent row is inserted before any referencing child row, or if two tables mutually reference each other within one transaction, have the DBA declare the foreign key `DEFERRABLE` and use `SET CONSTRAINTS ... DEFERRED`.

    They must show youthe transaction test log or `pg_constraint` row (`condeferrable`, `condeferred`) proving the parent and child writes commit without 23503.

    In writingthe statement ordering change or `SET CONSTRAINTS` configuration and the verified `pg_get_constraintdef` definition.

  2. Explicitly handle dependent child rows and index referencing columns when appropriate

    What they doBefore deleting a referenced row, have the developer or DBA either delete or reassign dependent child rows explicitly in the transaction, or after a backup, migrate the foreign key to an appropriate `ON DELETE` policy (`CASCADE`, `SET NULL`, or `RESTRICT`) and index the referencing column(s) if parent keys are updated or deleted frequently.

    They must show youthe `SELECT COUNT(*)` of dependent child rows before deletion and the `pg_get_constraintdef` output after any reviewed policy change.

    In writingthe chosen referential policy (`NO ACTION`, `RESTRICT`, `CASCADE`, or `SET NULL`), any index added on referencing columns, and backup verification.

Before accepting a part or repair

Nothing has been shown yet. Do not accept a part swap based on the code alone.

Follow these steps

Note: Follow the documented order. An error code identifies the affected system, but it does not prove by itself which part has failed.

  1. Inspect Constraint, Table, and Detail fields to determine the failure direction

    No special tools

    Who:
    Your developer or DBA reads the structured ErrorResponse fields from the failed statement.
    How:
    Capture fields `n` (Constraint name), `s` (Schema name), `t` (Table name), and `D` (Detail) using `\set VERBOSITY verbose` in `psql` or your database driver's error object.
    Result that matters:
    Field `n` identifies the exact foreign key constraint and `D` states whether a key is not present in the referenced table or is still referenced from a child table.
    If `D` reports that the key is not present in the referenced table during an `INSERT` or `UPDATE`, that confirms a child write referenced a missing or uncommitted parent row.
    If `D` reports that the key is still referenced from another table during a `DELETE` or `UPDATE`, that confirms existing dependent rows blocked removal of the parent key.
    Evidence to keep:
    Keep the verbatim `n`, `s`, `t`, and redacted `D` fields with the statement type (`INSERT`, `UPDATE`, or `DELETE`).

    Evidence: PostgreSQL 18 Appendix A: Error Codes · PostgreSQL error and notice fields · PostgreSQL bug reporting guidelines

  2. Check pg_constraint for referenced table, referential actions, and deferrability

    Tools required

    Who:
    Your DBA or developer runs a read-only catalog query on `pg_constraint`.
    How:
    Execute `SELECT conname, conrelid::regclass AS child_table, confrelid::regclass AS parent_table, confupdtype, confdeltype, confmatchtype, condeferrable, condeferred, pg_get_constraintdef(oid, true) FROM pg_constraint WHERE conname = '<constraint_name>' AND contype = 'f';`.
    Result that matters:
    `pg_constraint` records `confrelid` (referenced table), `confupdtype` and `confdeltype` (`a` = no action, `r` = restrict, `c` = cascade, `n` = set null, `d` = set default), `confmatchtype` (`f` = full, `s` = simple), and deferrability.
    If `confdeltype` is `a` or `r`, that confirms PostgreSQL will reject any `DELETE` on `parent_table` while matching rows remain in `child_table`.
    If `condeferrable` is `true` and `confdeltype` is `a` (NO ACTION), that indicates the check can be deferred until commit with `SET CONSTRAINTS`, whereas `r` (RESTRICT) never allows deferral.
    Evidence to keep:
    Save the `pg_constraint` query row including `pg_get_constraintdef` output.

    Run read-only catalog `SELECT` queries only; do not drop foreign keys or delete child rows before verifying business retention rules.

    Evidence: PostgreSQL constraints · PostgreSQL pg_constraint catalog · PostgreSQL 18 system information functions

  3. Verify parent-before-child ordering or deferred constraint mode inside the transaction

    No special tools

    Who:
    Your developer traces the order of SQL statements inside the transaction that raised 23503.
    How:
    Check whether the child `INSERT` ran before the parent `INSERT`, whether the parent transaction rolled back earlier, or whether cyclic foreign keys require `SET CONSTRAINTS <name> DEFERRED`.
    Result that matters:
    `REFERENCES` (foreign key) constraints are checked at the end of each statement by default (`NOT DEFERRABLE` or `INITIALLY IMMEDIATE`), and can only be postponed to transaction commit when declared `DEFERRABLE`.
    If the child row is inserted before its parent on a `NOT DEFERRABLE` foreign key, that confirms statement-order timing triggered 23503.
    If the parent row was supposedly created in a separate session that rolled back or has not committed yet, that isolates the problem to cross-session visibility or aborted work.
    Evidence to keep:
    Record the exact sequence of statements and transaction boundaries leading to the 23503 error.

    Evidence: PostgreSQL 18 SET CONSTRAINTS · PostgreSQL 18 CREATE TABLE

Still not solved

If the error persists, stop here. See what the technician must do and show you.

Virtual technician

Does 23503 still appear after these checks?

This guided flow uses the exact code and your answers to choose a test, an expected result and the next branch.

Where this code applies

A code is meaningful only inside the right product and version context.

Primary scope

System
Software and digital services
Brand
PostgreSQL
Product type
Databases

Known code variants

  • foreign_key_violation
  • PostgreSQL 23503
  • SQLSTATE 23503

What it means

Appendix A of the PostgreSQL documentation assigns SQLSTATE 23503 to `foreign_key_violation` in Class 23 (Integrity Constraint Violation). A foreign key constraint requires values in the referencing column(s) to match values in a primary key or unique constraint of the referenced table. Violation 23503 happens in two directions: inserting or updating a child row whose key has no matching parent row, or deleting/updating a referenced parent row while dependent child rows still exist under `NO ACTION` (the default) or `RESTRICT`. By itself, code 23503 does not prove which direction failed or whether transaction ordering, a rolled-back parent insert, or a `MATCH FULL` rule caused the mismatch.

Warnings and stop conditions

  • Highsource verified

    Never switch a foreign key to `ON DELETE CASCADE` or mark it `NOT ENFORCED` without reviewing what the tables represent; Section 5.5.5 warns that cascading a deletion across independent objects (such as deleting order history when a product is removed) can silently destroy critical records.

    Evidence: PostgreSQL constraints · PostgreSQL 18 CREATE TABLE

  • Lowsource verified

    Do not attempt to post raw `Detail` messages containing customer identifiers or keys to external issue trackers without redacting sensitive values first.

    Evidence: PostgreSQL error and notice fields · PostgreSQL bug reporting guidelines

Symptoms and causes

Probable causes · in order

  • An INSERT or UPDATE on the referencing table points to a parent key that does not existCommon

    Section 5.5.5 explains that a foreign key makes it impossible to create referencing rows with non-null key values that do not appear in the referenced table.

    Evidence: PostgreSQL constraints

  • A DELETE or UPDATE on the referenced table was blocked by dependent child rows under NO ACTION or RESTRICTCommon

    The default `ON DELETE NO ACTION` and `ON UPDATE NO ACTION` settings, as well as `RESTRICT`, produce an error if deleting or updating a referenced row leaves referencing rows without a valid parent match.

    Evidence: PostgreSQL constraints · PostgreSQL 18 CREATE TABLE

  • A multicolumn foreign key declared MATCH FULL received a mix of null and non-null columns, or a SET DEFAULT action lacked a matching parentPossible

    Under `MATCH FULL`, mixing null and non-null values in a multicolumn foreign key is guaranteed to fail, and `SET DEFAULT` also fails if the referenced table contains no row matching the default values.

    Evidence: PostgreSQL constraints · PostgreSQL 18 CREATE TABLE

Sources and technical references

  1. 1

    PostgreSQL 18 Appendix A: Error Codes

    PostgreSQL Global Development Group · 2026 · official_doc

  2. 2

    PostgreSQL constraints

    PostgreSQL Global Development Group · 2026 · official_doc

Sources: PostgreSQL 18 Appendix A: Error Codes · PostgreSQL constraintsreviewed 2026-10-19 · verified

Was this entry useful?