Skip to content

Supabase database errorSupabase: “violates foreign key constraint” (23503)

“violates foreign key constraint” is Postgres error 23503. An insert or update points at a row that doesn’t exist, or a delete would leave rows pointing at nothing. In Supabase it shows up most when saving a profile before the user exists, or when deleting a user.

Short answer

Read the Detail line. “is not present in table” is an insert problem, and “is still referenced from table” is a delete problem. On insert, create the parent row first and check the ID you send, such as auth.uid() for a profile. On delete, choose what should happen to the child rows and set it on the foreign key, such as on delete cascade for a profile tied to auth.users. Then run the delete again.

Rather not fix it yourself? App Fix Ticket starts with a fixed-price diagnosis, then a fixed price for the fix before any fix work.

Why the row is refused, and the fix

  1. 01

    The insert points at a row that doesn’t exist

    “A foreign key constraint specifies that the values in a column (or a group of columns) must match the values appearing in some row of another table.” PostgreSQL docs, Constraints (foreign keys)

    The ID in the new row has no match in the table it references. Common cases: a profile saved with an ID from another project, a child saved before its parent, or seed data in the wrong order.

  2. 02

    Deleting a user who still has rows

    “Reference the auth.users table to ensure data integrity. Specify on delete cascade in the reference.” Supabase, User management

    Without an on delete rule, Postgres refuses to delete a row that other rows reference. For data that belongs to the user, drop the constraint and add it back with on delete cascade. profiles_id_fkey is only the default name, so check the real one in the table’s constraints first.

    alter table public.profiles
      drop constraint profiles_id_fkey,
      add constraint profiles_id_fkey
        foreign key (id) references auth.users (id) on delete cascade;
  3. 03

    Pick the right on delete rule

    “The default ON DELETE action is ON DELETE NO ACTION; this does not need to be specified.” PostgreSQL docs, Constraints (foreign keys)

    Cascade removes the child rows. Set null keeps them with an empty link, for example orders you need to keep for tax records, and needs a column that allows null. The default blocks the delete.

  4. 04

    The user owns files in Storage

    “You cannot delete a user if they are the owner of any objects in Supabase Storage.” Supabase, User management

    A user delete can also fail on Storage. Delete or move the user’s files first, then delete the user.

  5. 05

    Point keys at id to avoid this later

    “Only use primary keys as foreign key references for schemas and tables like auth.users which are managed by Supabase.” Supabase, User management

    Point foreign keys to auth.users at its id column, not at email or another field that Supabase can update, so rows don’t end up pointing at nothing.

Checked against the vendor’s docs on : PostgreSQL docs: Constraints (foreign keys); Supabase docs: User management.

Rather hand it over?

Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.

“Very responsive, attentive to fixing bugs, and completed the project as needed! Thank you!”
A buyer in the United States, July 2022. Shopify on Fiverr
All 127 Fiverr reviews

Related: Supabase violates not-null constraint · Supabase duplicate key violates unique constraint · Supabase “Database error saving new user” · Supabase operator does not exist: uuid = text

Questions

More on this error

Is it safe to add on delete cascade?

It is safe for rows that only make sense with the parent, such as a profile. For records you must keep, use set null, or delete the children yourself first.

Does changing the constraint touch existing rows?

Adding it back checks the rows that are already there, so the migration fails if any row points at a missing parent. Fix or delete those rows first.

Can you fix it for me?

If one bug is the whole problem, the App Fix Ticket covers it: a written diagnosis first, then the fix. If the app has more going on, the Launch Check is a written check of the whole app. Each issue found is rated critical, high, medium or low, with where it is and how it was confirmed. 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.

A different error?

Describe it and get a written quote

Send the error and what you were doing. You get a written scope, a fixed price and a timeline; Simon replies by email, usually within one business day.