Make the logical replication conflict messages more like each other

From: Peter Smith <smithpb2250(at)gmail(dot)com>
To: PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Subject: Make the logical replication conflict messages more like each other
Date: 2026-05-18 23:08:18
Message-ID: CAHut+PuX_pPF6mU-UPRdQQToGgUPRpbOxOEFxPVC7B5Tevb-9A@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi,

(This was first suggested by me in thread [1], but it was deemed out
of scope, so I have now separated it here.)

I was looking at the many messages related to logical replication
conflicts (in conflict.c, function errdetail_apply_conflict).
Currently, the wording for the errmsgdetail seems a bit inconsistent
to me. I felt that because all of these messages are closely related,
they should all resemble each other more than they do now.

~~~

CURRENT

CT_INSERT_EXISTS
CT_UPDATE_EXISTS
CT_MULTIPLE_UNIQUE_CONFLICTS
* Could not apply remote change: %s.\n
* Could not apply remote change.\n
- Key already exists in unique index \"%s\", modified locally in
transaction %u at %s: %s.
- Key already exists in unique index \"%s\", modified locally in
transaction %u at %s.
- Key already exists in unique index \"%s\", modified by origin \"%s\"
in transaction %u at %s: %s.
- Key already exists in unique index \"%s\", modified by origin \"%s\"
in transaction %u at %s.
- Key already exists in unique index \"%s\", modified by a
non-existent origin in transaction %u at %s: %s.
- Key already exists in unique index \"%s\", modified by a
non-existent origin in transaction %u at %s.
- Key already exists in unique index \"%s\", modified in transaction %u: %s.
- Key already exists in unique index \"%s\", modified in transaction %u.

CT_UPDATE_ORIGIN_DIFFERS
- Updating the row that was modified locally in transaction %u at %s: %s.
- Updating the row that was modified locally in transaction %u at %s.
- Updating the row that was modified by a different origin \"%s\" in
transaction %u at %s: %s.
- Updating the row that was modified by a different origin \"%s\" in
transaction %u at %s.
- Updating the row that was modified by a non-existent origin in
transaction %u at %s: %s.
- Updating the row that was modified by a non-existent origin in
transaction %u at %s.

CT_UPDATE_DELETED
* Could not find the row to be updated: %s.\n
* Could not find the row to be updated.\n
- The row to be updated was deleted locally in transaction %u at %s
- The row to be updated was deleted by a different origin \"%s\" in
transaction %u at %s
- The row to be updated was deleted by a non-existent origin in
transaction %u at %s
- The row to be updated was deleted

CT_UPDATE_MISSING
* Could not find the row to be updated: %s.
* Could not find the row to be updated.

CT_DELETE_ORIGIN_DIFFERS
- Deleting the row that was modified locally in transaction %u at %s: %s.
- Deleting the row that was modified locally in transaction %u at %s.
- Deleting the row that was modified by a different origin \"%s\" in
transaction %u at %s: %s.
- Deleting the row that was modified by a different origin \"%s\" in
transaction %u at %s.
- Deleting the row that was modified by a non-existent origin in
transaction %u at %s: %s.
- Deleting the row that was modified by a non-existent origin in
transaction %u at %s.

CT_DELETE_MISSING
* Could not find the row to be deleted: %s.
* Could not find the row to be deleted.

~~~

Some proposed changes:
e.g. Only some cases (CT_UPDATE_DELETED, CT_INSERT_EXISTS,
CT_UPDATE_EXISTS, etc.) currently give the general reason, followed on
the next line by the details for the conflict. I think all these
conflict messages should use this pattern
e.g. All errdetail messages should have a period to terminate them.
e.g. Use more consistent wording for all conflicts: "The row to
update", "The row to delete", etc.
e.g. The words "the row to be updated" do not need to be repeated for
the same conflict message.
e.g. The suggested wording makes the messages much closer to the DOCS
[2] descriptions

(Compare the CURRENT messages above with the following SUGGESTIONS below)

SUGGESTIONS (or something like this...)

CT_INSERT_EXISTS
CT_UPDATE_EXISTS
CT_MULTIPLE_UNIQUE_CONFLICTS
* The row to insert violates a constraint: %s.\n
* The row to insert violates a constraint.\n
* The row to update violates a constraint: %s.\n
* The row to update violates a constraint.\n
* The row to insert or update violates a constraint: %s.\n
* The row to insert or update violates a constraint.\n
- Key already exists in unique index \"%s\", modified locally in
transaction %u at %s: %s.
- Key already exists in unique index \"%s\", modified locally in
transaction %u at %s.
- Key already exists in unique index \"%s\", modified by origin \"%s\"
in transaction %u at %s: %s.
- Key already exists in unique index \"%s\", modified by origin \"%s\"
in transaction %u at %s.
- Key already exists in unique index \"%s\", modified by a
non-existent origin in transaction %u at %s: %s.
- Key already exists in unique index \"%s\", modified by a
non-existent origin in transaction %u at %s.
- Key already exists in unique index \"%s\", modified in transaction %u: %s.
- Key already exists in unique index \"%s\", modified in transaction %u.

CT_UPDATE_ORIGIN_DIFFERS
* The row to update was modified by another origin.\n
- It was modified locally in transaction %u at %s: %s.
- It was modified locally in transaction %u at %s.
- It was modified by a different origin \"%s\" in transaction %u at %s: %s.
- It was modified by a different origin \"%s\" in transaction %u at %s.
- It was modified by a non-existent origin in transaction %u at %s: %s.
- It was modified by a non-existent origin in transaction %u at %s.

CT_UPDATE_DELETED
* The row to update was already deleted: %s.\n
* The row to update was already deleted.\n
- It was deleted locally in transaction %u at %s.
- It was deleted by a different origin \"%s\" in transaction %u at %s.
- It was deleted by a non-existent origin in transaction %u at %s.

CT_UPDATE_MISSING
* The row to update was not found: %s.
* The row to update was not found.

CT_DELETE_ORIGIN_DIFFERS
* The row to delete was modified by another origin.\n
- It was modified locally in transaction %u at %s: %s.
- It was modified locally in transaction %u at %s.
- It was modified by a different origin \"%s\" in transaction %u at %s: %s.
- It was modified by a different origin \"%s\" in transaction %u at %s.
- It was modified by a non-existent origin in transaction %u at %s: %s.
- It was modified by a non-existent origin in transaction %u at %s.

CT_DELETE_MISSING
* The row to delete was not found: %s.
* The row to delete was not found.

~~~

Anyway, this is just a suggestion. I won't make the patch for this
unless/until there is agreement that proceeding would be worthwhile.

======
[1] https://www.postgresql.org/message-id/CAHut%2BPvicB-bAqo4XpsPOnr%3DLi_jop6i4kpcy%2BVK_MYsEFFeqg%40mail.gmail.com
[2] https://www.postgresql.org/docs/devel/logical-replication-conflicts.html

Kind Regards,
Peter Smith.
Fujitsu Australia.

Browse pgsql-hackers by date

  From Date Subject
Next Message Greg Burd 2026-05-19 00:12:33 Re: duckdb has extensible parser
Previous Message Chao Li 2026-05-18 22:27:54 Re: COPY FROM ON_ERROR SET_NULL bypasses domain NOT NULL with partial column list