Description
Every time metadata is refreshed, Postgres logs thousands of duplicate key errors for the metadata_to_metadata table.
The insert uses ON CONFLICT ("id") DO NOTHING, but the unique constraint that is actually violated is the composite index on (from_metadata_id, relation, to_metadata_id).
Because id is always new, the conflict clause never matches, and every already-existing suggestion raises an error instead of being silently skipped.
Expected behaviour
Re-inserting an existing relation should be a no-op.
Actual behaviour
Postgres rejects each row individually and logs one error per row.
Logs
ERROR: duplicate key value violates unique constraint
"metadata_to_metadata_from_metadata_id_relation_to_metadata__idx"
DETAIL: Key (from_metadata_id, relation, to_metadata_id)=
(met_hgjFdwJP-XZt, suggestion, met_--E5lqYffHN4) already exists.
STATEMENT: INSERT INTO "metadata_to_metadata"
("from_metadata_id", "relation", "to_metadata_id")
VALUES ($1, $2, $3) ON CONFLICT ("id") DO NOTHING
Impact
No data loss — the row already exists, so nothing is actually missing. But it generates a lot of noise and wasted database work:
- ~13,500 errors per refresh cycle
- 2 cycles in 3 days (26 Jul 03:00 and 27 Jul 17:00, local time)
- roughly 20% of that day's total log volume across my whole stack
I only noticed because a log-volume alert fired. Otherwise it is completely silent.
Suggested fix
Target the composite unique index instead of the primary key:
ON CONFLICT (from_metadata_id, relation, to_metadata_id) DO NOTHING
Environment
- Ryot: v10.4.0 (
ghcr.io/ignisda/ryot:latest)
- Database: postgres:16-alpine
- Deployment: Docker, self-hosted
Description
Every time metadata is refreshed, Postgres logs thousands of
duplicate keyerrors for themetadata_to_metadatatable.The insert uses
ON CONFLICT ("id") DO NOTHING, but the unique constraint that is actually violated is the composite index on(from_metadata_id, relation, to_metadata_id).Because
idis always new, the conflict clause never matches, and every already-existing suggestion raises an error instead of being silently skipped.Expected behaviour
Re-inserting an existing relation should be a no-op.
Actual behaviour
Postgres rejects each row individually and logs one error per row.
Logs
Impact
No data loss — the row already exists, so nothing is actually missing. But it generates a lot of noise and wasted database work:
I only noticed because a log-volume alert fired. Otherwise it is completely silent.
Suggested fix
Target the composite unique index instead of the primary key:
ON CONFLICT (from_metadata_id, relation, to_metadata_id) DO NOTHINGEnvironment
ghcr.io/ignisda/ryot:latest)