pg_restore failed on foreign key constraint

Started by Ron2 months ago9 messagesgeneral
Jump to latest
#1Ron
ronljohnsonjr@gmail.com

When running pg_restore 17.7 against a PG 14.20 database directory dump, I
got this in the log:

pg_restore: while PROCESSING TOC:
pg_restore: from TOC entry 171927; 2606 3149123877 FK CONSTRAINT
rel_user_email fk_rel_user_email_2 TAP
pg_restore: error: could not execute query: ERROR: insert or update on
table "rel_user_email" violates foreign key constraint "fk_rel_user_email_2"
DETAIL: Key (access_email_id)=(2073) is not present in table
"access_email".
Command was: ALTER TABLE ONLY public.rel_user_email
ADD CONSTRAINT fk_rel_user_email_2 FOREIGN KEY (access_email_id)
REFERENCES public.access_email(access_email_id);

So, I went to the source database:

TAPd=# \d rel_user_email
Table "public.rel_user_email"
Column | Type | Collation | Nullable |
Default
-----------------+-----------------------------+-----------+----------+---------
user_id | integer | | not null |
access_email_id | integer | | not null |
modified_by | integer | | |
modified_on | timestamp without time zone | | not null |
Indexes:
"idx_rel_user_email" UNIQUE, btree (user_id, access_email_id)
Foreign-key constraints:
"fk_rel_user_email_1" FOREIGN KEY (user_id) REFERENCES
access_user(user_id)
"fk_rel_user_email_2" FOREIGN KEY (access_email_id) REFERENCES
access_email(access_email_id)

TAPd=# select * from rel_user_email where access_email_id=2073;
user_id | access_email_id | modified_by | modified_on
---------+-----------------+-------------+-------------------------
2452 | 2073 | 41 | 2013-03-11 10:52:20.331
(1 row)

TAPd=# \d access_email
Table "public.access_email"
Column | Type | Collation | Nullable |
Default
-----------------+-----------------------------+-----------+----------+-------------------------------------------------------
access_email_id | integer | | not null |
nextval('access_email_access_email_id_seq'::regclass)
type | numeric(10,0) | | |
email_address | character varying(255) | | |
created_on | timestamp without time zone | | not null |
modified_on | timestamp without time zone | | |
created_by | integer | | |
modified_by | integer | | |
Indexes:
"pk_access_email" PRIMARY KEY, btree (access_email_id)
Referenced by:
TABLE "rel_user_email" CONSTRAINT "fk_rel_user_email_2" FOREIGN KEY
(access_email_id) REFERENCES access_email(access_email_id)

TAPd=# select * from access_email where access_email_id=2073;
access_email_id | type | email_address | created_on | modified_on |
created_by | modified_by
-----------------+------+---------------+------------+-------------+------------+-------------
(0 rows)

Looks like index corruption.

$ pg_amcheck -t public.rel_user_email -t public.access_email TAPd
$ echo $?
0
$ pg_amcheck -i idx_rel_user_email -i pk_access_email --parent-check
--heapallindexed TAPd
$ echo $?
0

But amcheck shows no problems.

Before I get worried that there' s corrupt data: am I missing something
obvious?

--
Death to <Redacted>, and butter sauce.
Don't boil me, I'm still alive.
<Redacted> lobster!

#2Laurenz Albe
laurenz.albe@cybertec.at
In reply to: Ron (#1)
Re: pg_restore failed on foreign key constraint

On Thu, 2026-02-12 at 16:35 -0500, Ron Johnson wrote:

When running pg_restore 17.7 against a PG 14.20 database directory dump, I got this in the log:

pg_restore: while PROCESSING TOC:
pg_restore: from TOC entry 171927; 2606 3149123877 FK CONSTRAINT rel_user_email fk_rel_user_email_2 TAP
pg_restore: error: could not execute query: ERROR:  insert or update on table "rel_user_email" violates foreign key constraint "fk_rel_user_email_2"
DETAIL:  Key (access_email_id)=(2073) is not present in table "access_email".
Command was: ALTER TABLE ONLY public.rel_user_email
    ADD CONSTRAINT fk_rel_user_email_2 FOREIGN KEY (access_email_id) REFERENCES public.access_email(access_email_id);

So, I went to the source database:

TAPd=# \d rel_user_email
                         Table "public.rel_user_email"
     Column      |            Type             | Collation | Nullable | Default
-----------------+-----------------------------+-----------+----------+---------
 user_id         | integer                     |           | not null |
 access_email_id | integer                     |           | not null |
 modified_by     | integer                     |           |          |
 modified_on     | timestamp without time zone |           | not null |
Indexes:
    "idx_rel_user_email" UNIQUE, btree (user_id, access_email_id)
Foreign-key constraints:
    "fk_rel_user_email_1" FOREIGN KEY (user_id) REFERENCES access_user(user_id)
    "fk_rel_user_email_2" FOREIGN KEY (access_email_id) REFERENCES access_email(access_email_id)

TAPd=# select * from rel_user_email where access_email_id=2073;
 user_id | access_email_id | modified_by |       modified_on      
---------+-----------------+-------------+-------------------------
    2452 |            2073 |          41 | 2013-03-11 10:52:20.331
(1 row)

TAPd=# \d access_email
                                                 Table "public.access_email"
     Column      |            Type             | Collation | Nullable |                        Default                        
-----------------+-----------------------------+-----------+----------+-------------------------------------------------------
 access_email_id | integer                     |           | not null | nextval('access_email_access_email_id_seq'::regclass)
 type            | numeric(10,0)               |           |          |
 email_address   | character varying(255)      |           |          |
 created_on      | timestamp without time zone |           | not null |
 modified_on     | timestamp without time zone |           |          |
 created_by      | integer                     |           |          |
 modified_by     | integer                     |           |          |
Indexes:
    "pk_access_email" PRIMARY KEY, btree (access_email_id)
Referenced by:
    TABLE "rel_user_email" CONSTRAINT "fk_rel_user_email_2" FOREIGN KEY (access_email_id) REFERENCES access_email(access_email_id)

TAPd=# select * from access_email where access_email_id=2073;
 access_email_id | type | email_address | created_on | modified_on | created_by | modified_by
-----------------+------+---------------+------------+-------------+------------+-------------
(0 rows)

Looks like index corruption.  

$ pg_amcheck -t public.rel_user_email -t public.access_email TAPd
$ echo $?
0
$ pg_amcheck -i idx_rel_user_email -i pk_access_email --parent-check --heapallindexed TAPd
$ echo $?
0

But amcheck shows no problems.

Before I get worried that there' s corrupt data: am I missing something obvious?

Try

SET enable_indexscan = off;

SELECT * FROM access_email WHERE access_email_id = 2073;

Only if that returns a row, I would assume index corruption, and that one should have been
caught with "heapallindexed".

It is the foreign key that is violated. The normal ways to end up with broken foreign
keys are

SET session_replication_role = replica;

and

ALTER TABLE rel_user_email DISABLE TRIGGER ALL;

both of which require superuser privileges.

Yours,
Laurenz Albe

#3Ron
ronljohnsonjr@gmail.com
In reply to: Laurenz Albe (#2)
Re: pg_restore failed on foreign key constraint

On Fri, Feb 13, 2026 at 1:43 AM Laurenz Albe <laurenz.albe@cybertec.at>
wrote:

On Thu, 2026-02-12 at 16:35 -0500, Ron Johnson wrote:

When running pg_restore 17.7 against a PG 14.20 database directory dump,

I got this in the log:

pg_restore: while PROCESSING TOC:
pg_restore: from TOC entry 171927; 2606 3149123877 FK CONSTRAINT

rel_user_email fk_rel_user_email_2 TAP

pg_restore: error: could not execute query: ERROR: insert or update on

table "rel_user_email" violates foreign key constraint "fk_rel_user_email_2"

DETAIL: Key (access_email_id)=(2073) is not present in table

"access_email".

Command was: ALTER TABLE ONLY public.rel_user_email
ADD CONSTRAINT fk_rel_user_email_2 FOREIGN KEY (access_email_id)

REFERENCES public.access_email(access_email_id);

So, I went to the source database:

TAPd=# \d rel_user_email
Table "public.rel_user_email"
Column | Type | Collation | Nullable |

Default

-----------------+-----------------------------+-----------+----------+---------

user_id | integer | | not null |
access_email_id | integer | | not null |
modified_by | integer | | |
modified_on | timestamp without time zone | | not null |
Indexes:
"idx_rel_user_email" UNIQUE, btree (user_id, access_email_id)
Foreign-key constraints:
"fk_rel_user_email_1" FOREIGN KEY (user_id) REFERENCES

access_user(user_id)

"fk_rel_user_email_2" FOREIGN KEY (access_email_id) REFERENCES

access_email(access_email_id)

TAPd=# select * from rel_user_email where access_email_id=2073;
user_id | access_email_id | modified_by | modified_on
---------+-----------------+-------------+-------------------------
2452 | 2073 | 41 | 2013-03-11 10:52:20.331
(1 row)

TAPd=# \d access_email
Table

"public.access_email"

Column | Type | Collation | Nullable |

Default

-----------------+-----------------------------+-----------+----------+-------------------------------------------------------

access_email_id | integer | | not null |

nextval('access_email_access_email_id_seq'::regclass)

type | numeric(10,0) | | |
email_address | character varying(255) | | |
created_on | timestamp without time zone | | not null |
modified_on | timestamp without time zone | | |
created_by | integer | | |
modified_by | integer | | |
Indexes:
"pk_access_email" PRIMARY KEY, btree (access_email_id)
Referenced by:
TABLE "rel_user_email" CONSTRAINT "fk_rel_user_email_2" FOREIGN KEY

(access_email_id) REFERENCES access_email(access_email_id)

TAPd=# select * from access_email where access_email_id=2073;
access_email_id | type | email_address | created_on | modified_on |

created_by | modified_by

-----------------+------+---------------+------------+-------------+------------+-------------

(0 rows)

Looks like index corruption.

$ pg_amcheck -t public.rel_user_email -t public.access_email TAPd
$ echo $?
0
$ pg_amcheck -i idx_rel_user_email -i pk_access_email --parent-check

--heapallindexed TAPd

$ echo $?
0

But amcheck shows no problems.

Before I get worried that there' s corrupt data: am I missing something

obvious?

Try

SET enable_indexscan = off;

SELECT * FROM access_email WHERE access_email_id = 2073;

Only if that returns a row, I would assume index corruption, and that one
should have been
caught with "heapallindexed".

It is the foreign key that is violated. The normal ways to end up with
broken foreign
keys are

SET session_replication_role = replica;

and

ALTER TABLE rel_user_email DISABLE TRIGGER ALL;

both of which require superuser privileges.

Turns out that there's a nightly cron job that dumps this (and other)
tables with the "--data-only --disable-triggers" options and then does
"psql -Xaf mumble.sql" to load them into this database.

But access_email_id=2073 is in the source access_email, so I've got to
figure out why it's not being loaded into the target.

--
Death to <Redacted>, and butter sauce.
Don't boil me, I'm still alive.
<Redacted> lobster!

#4Adrian Klaver
adrian.klaver@aklaver.com
In reply to: Ron (#3)
Re: pg_restore failed on foreign key constraint

On 2/13/26 06:18, Ron Johnson wrote:

On Fri, Feb 13, 2026 at 1:43 AM Laurenz Albe <laurenz.albe@cybertec.at
<mailto:laurenz.albe@cybertec.at>> wrote:

Turns out that there's a nightly cron job that dumps this (and other)
tables with the "--data-only --disable-triggers" options and then does
"psql -Xaf mumble.sql" to load them into this database.

But access_email_id=2073 is in the source access_email, so I've got to
figure out why it's not being loaded into the target.

Is it in the dump file from the source?

--
Death to <Redacted>, and butter sauce.
Don't boil me, I'm still alive.
<Redacted> lobster!

--
Adrian Klaver
adrian.klaver@aklaver.com

#5Ron
ronljohnsonjr@gmail.com
In reply to: Adrian Klaver (#4)
Re: pg_restore failed on foreign key constraint

On Fri, Feb 13, 2026 at 10:55 AM Adrian Klaver <adrian.klaver@aklaver.com>
wrote:

On 2/13/26 06:18, Ron Johnson wrote:

On Fri, Feb 13, 2026 at 1:43 AM Laurenz Albe <laurenz.albe@cybertec.at
<mailto:laurenz.albe@cybertec.at>> wrote:

Turns out that there's a nightly cron job that dumps this (and other)
tables with the "--data-only --disable-triggers" options and then does
"psql -Xaf mumble.sql" to load them into this database.

But access_email_id=2073 is in the source access_email, so I've got to
figure out why it's not being loaded into the target.

Is it in the dump file from the source?

Some tables aren't being dumped at the source; Thus, the missing records.

--
Death to <Redacted>, and butter sauce.
Don't boil me, I'm still alive.
<Redacted> lobster!

#6Adrian Klaver
adrian.klaver@aklaver.com
In reply to: Ron (#5)
Re: pg_restore failed on foreign key constraint

On 2/13/26 08:05, Ron Johnson wrote:

On Fri, Feb 13, 2026 at 10:55 AM Adrian Klaver
<adrian.klaver@aklaver.com <mailto:adrian.klaver@aklaver.com>> wrote:

On 2/13/26 06:18, Ron Johnson wrote:

On Fri, Feb 13, 2026 at 1:43 AM Laurenz Albe

<laurenz.albe@cybertec.at <mailto:laurenz.albe@cybertec.at>

<mailto:laurenz.albe@cybertec.at

<mailto:laurenz.albe@cybertec.at>>> wrote:

Turns out that there's a nightly cron job that dumps this (and

other)

tables with the "--data-only --disable-triggers" options and then

does

"psql -Xaf mumble.sql" to load them into this database.

But access_email_id=2073 is in the source access_email, so I've

got to

figure out why it's not being loaded into the target.

Is it in the dump file from the source?

Some tables aren't being dumped at the source;  Thus, the missing records.

Un-confuse me, how do the below relate?:

"Turns out that there's a nightly cron job that dumps this (and other)
tables with the "--data-only --disable-triggers" options and then does
"psql -Xaf mumble.sql" to load them into this database.

But access_email_id=2073 is in the source access_email, so I've got to
figure out why it's not being loaded into the target."

and

"Some tables aren't being dumped at the source"

--
Death to <Redacted>, and butter sauce.
Don't boil me, I'm still alive.
<Redacted> lobster!

--
Adrian Klaver
adrian.klaver@aklaver.com

#7Ron
ronljohnsonjr@gmail.com
In reply to: Adrian Klaver (#6)
Re: pg_restore failed on foreign key constraint

On Fri, Feb 13, 2026 at 11:14 AM Adrian Klaver <adrian.klaver@aklaver.com>
wrote:

On 2/13/26 08:05, Ron Johnson wrote:

On Fri, Feb 13, 2026 at 10:55 AM Adrian Klaver
<adrian.klaver@aklaver.com <mailto:adrian.klaver@aklaver.com>> wrote:

On 2/13/26 06:18, Ron Johnson wrote:

On Fri, Feb 13, 2026 at 1:43 AM Laurenz Albe

<laurenz.albe@cybertec.at <mailto:laurenz.albe@cybertec.at>

<mailto:laurenz.albe@cybertec.at

<mailto:laurenz.albe@cybertec.at>>> wrote:

Turns out that there's a nightly cron job that dumps this (and

other)

tables with the "--data-only --disable-triggers" options and then

does

"psql -Xaf mumble.sql" to load them into this database.

But access_email_id=2073 is in the source access_email, so I've

got to

figure out why it's not being loaded into the target.

Is it in the dump file from the source?

Some tables aren't being dumped at the source; Thus, the missing

records.

Un-confuse me, how do the below relate?:

"Turns out that there's a nightly cron job that dumps this (and other)
tables with the "--data-only --disable-triggers" options and then does
"psql -Xaf mumble.sql" to load them into this database.

But access_email_id=2073 is in the source access_email, so I've got to
figure out why it's not being loaded into the target."

and

"Some tables aren't being dumped at the source"

Table name Source Dumped Target Loaded
public.access_email No No
public.rel_user_email Yes Yes

Thus, while new and modified records are being added to public.access_email
at the source, they are not making it to the Target database. That plus
"--disable-triggers" lets the public.rel_user_email loads succeed on the
target even though it breaks RI.

--
Death to <Redacted>, and butter sauce.
Don't boil me, I'm still alive.
<Redacted> lobster!

#8Adrian Klaver
adrian.klaver@aklaver.com
In reply to: Ron (#7)
Re: pg_restore failed on foreign key constraint

On 2/13/26 8:40 AM, Ron Johnson wrote:

On Fri, Feb 13, 2026 at 11:14 AM Adrian Klaver

Un-confuse me, how do the below relate?:

"Turns out that there's a nightly cron job that dumps this (and other)
tables with the "--data-only --disable-triggers" options and then does
"psql -Xaf mumble.sql" to load them into this database.

But access_email_id=2073 is in the source access_email, so I've got to
figure out why it's not being loaded into the target."

and

"Some tables aren't being dumped at the source"

Table name            Source Dumped   Target Loaded
public.access_email   No              No
public.rel_user_email Yes             Yes

Thus, while new and modified records are being added
to public.access_email at the source, they are not making it to the
Target database.  That plus "--disable-triggers" lets
the public.rel_user_email loads succeed on the target even though it
breaks RI.

This means you know what the issue is now?

Show quoted text

--
Death to <Redacted>, and butter sauce.
Don't boil me, I'm still alive.
<Redacted> lobster!

#9Ron
ronljohnsonjr@gmail.com
In reply to: Adrian Klaver (#8)
Re: pg_restore failed on foreign key constraint

On Fri, Feb 13, 2026 at 12:35 PM Adrian Klaver <adrian.klaver@aklaver.com>
wrote:
[snip]

Thus, while new and modified records are being added
to public.access_email at the source, they are not making it to the
Target database. That plus "--disable-triggers" lets
the public.rel_user_email loads succeed on the target even though it
breaks RI.

This means you know what the issue is now?

Yes it does. 😀

--
Death to <Redacted>, and butter sauce.
Don't boil me, I'm still alive.
<Redacted> lobster!