Short answer
If the constraint ends in _pkey and the id is generated, compare max(id) with the next sequence value and reset the sequence with setval. If it names another column, find out why the same row is inserted twice: a double submit, a webhook delivered again, or a trigger and the app both creating the same profile. Then use an upsert or on conflict do nothing.
Read the constraint name, then fix the cause
01
A _pkey error after an import: the sequence fell behind
“it likely means that the table's sequence has somehow become out of sync, likely because of a mass import process (or something along those lines).” Supabase, Inserting into Sequence/Serial Table Causes "duplicate key violates unique constraint" Error
Rows imported or restored with their ids, or seed scripts that set ids by hand, don’t move the counter that hands out new ids. The next insert gets an id that is already taken. It only hits tables whose id is generated, and it keeps failing until the sequence is reset.
02
Check the sequence, then reset it
“This error suggests a discrepancy between the sequence-generated IDs and the actual IDs in the table.” Supabase, Why are there gaps in my Postgres id sequence?
Run this in the SQL editor with your table and column. If the next value is not higher than the largest id, move the sequence up to the largest id, so the next new row gets a free number. Supabase suggests taking a backup first.
select max(id) from public.orders; select nextval(pg_get_serial_sequence('public.orders', 'id')); select setval( pg_get_serial_sequence('public.orders', 'id'), (select max(id) from public.orders) );03
Any other constraint, or a _pkey on an id you set: the row really exists
“ON CONFLICT can be used to specify an alternative action to raising a unique constraint or exclusion constraint violation error.” PostgreSQL, INSERT
An error on users_email_key, or on profiles_pkey where the id comes from the signed-in user, means the insert repeats a value that must be unique. The usual sources are a button tapped twice, a Stripe webhook delivered more than once, or a profile row created by a trigger on sign-up and again by the app. Decide which write should win, and make the other one safe to repeat. In SQL:
-- inside a sign-up trigger function: keep the first row insert into public.profiles (id, username) values (new.id, new.raw_user_meta_data ->> 'username') on conflict (id) do nothing;04
From the app: upsert instead of insert
In supabase-js, upsert with onConflict updates the row when it already exists. Under RLS it needs both an insert policy and an update policy for the user, or it fails.
await supabase.from('profiles').upsert( { id: user.id, username }, { onConflict: 'id' } );05
Don’t paper over it
“sequences guarantee uniqueness, but not consecutiveness” Supabase, Why are there gaps in my Postgres id sequence?
Catching 23505 and ignoring it hides the double write, and an upsert that runs where the first write should have won can overwrite good data. Fix the duplicate at its source: disable the button while saving, record processed webhook event ids, or let only the trigger create profiles. Gaps in ids after a fix are normal.
Checked against the vendor’s docs on : Supabase troubleshooting: duplicate key violates unique constraint on a sequence table; Supabase troubleshooting: Why are there gaps in my Postgres id sequence?; PostgreSQL docs: INSERT … ON CONFLICT.
Rather hand it over?
Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.
- from $450App Fix TicketOne reproducible bug in an existing mobile or web app, diagnosed and fixed.See scope and start
- from $450AI-Built App RescueA Lovable, Bolt or Cursor app checked end to end in 3 days, then its worst problems fixed at a fixed price.No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.See scope and start
Related: Supabase “Database error saving new user” · Stripe webhook returns 200 but the database isn’t updated · Supabase “User already registered” · Supabase new row violates RLS