duplicate key value violates unique constraint "buckets_pkey"
What it means
This means you tried to insert a row into storage.buckets whose primary key (the bucket id) already exists. During a migration it usually happens because the destination project already has the default buckets, or the migration re-ran and tried to create the same bucket twice.
Why it happens
duplicate key value violates unique constraint "buckets_pkey" (SQLSTATE 23505) fires when an insert into storage.buckets uses a bucket id that already exists. The primary key on storage.buckets is the bucket id (its name), so two rows can't share it.
In a migration this happens when:
- The destination project already has the bucket — either a default bucket or one created earlier in a partial run.
- The migration is not idempotent and gets re-run after a failure, replaying the same
inserta second time.
How to fix it
Make the bucket creation idempotent so re-runs are safe. The cleanest way is on conflict:
insert into storage.buckets (id, name, public)
values ('avatars', 'avatars', true)
on conflict (id) do nothing;
If you also want to keep the destination's settings in sync with the source, upsert instead:
insert into storage.buckets (id, name, public, file_size_limit, allowed_mime_types)
values ('avatars', 'avatars', true, 5242880, array['image/png','image/jpeg'])
on conflict (id) do update
set public = excluded.public,
file_size_limit = excluded.file_size_limit,
allowed_mime_types = excluded.allowed_mime_types;
Check what already exists before deciding:
select id, name, public from storage.buckets order by id;
How to prevent it
- Always create buckets with
on conflict (id) do nothing(or an upsert) so the step is idempotent and safe to retry. - Move bucket objects separately from bucket definitions — create the bucket once, then copy files into it.
- Never assume a fresh Supabase project is empty: it ships with some defaults, and a retried migration may have created rows already.
Frequently asked questions
- Will this error lose my storage data?
- No. A unique-violation aborts only the offending statement (or its transaction). Nothing is deleted — Postgres refused to create a second bucket row with an id that already exists.
- Should I just delete the existing bucket?
- Usually not. Prefer an idempotent insert (on conflict do nothing) or upsert so re-running the migration is safe. Only delete a bucket if you are certain it is empty and unwanted.
Related errors