Supabase PGRST116: .single() did not get exactly one row

A Supabase query fails with PGRST116 or HTTP 406? .single() asked for one row and the database returned zero or more than one.

Reviewed October 15, 2026

What it means in plain English

.single() tells PostgREST to return one object instead of a list. Supabase's reference says the query must be one row, otherwise it returns an error. PostgREST's error list defines PGRST116 as HTTP 406: more than one item, or no items, came back when a singular response was requested.

An empty profile, a missing row, or two rows that share the filter all look like a broken page. The query ran. The shape was wrong.

Likely causes

  • The AI chained .single() onto a select that can match nothing, such as a profile that has not been created yet.
  • The filter matches more than one row, and there is no .limit(1) that actually leaves a single row. Supabase's example uses .limit(1) before .single().
  • .maybeSingle() was not used. That method allows zero or one row. Supabase says it still errors when more than one row comes back.

How to fix it, step by step

  1. Read the JSON body. Code PGRST116 means the singular request did not get exactly one row.
  2. If zero rows is a normal "nothing here yet" result, use .maybeSingle() and handle data === null.
  3. If you truly need one row, filter on a unique column, or use .limit(1) and still only call .single() when a row must exist.
  4. If several rows match, drop .single() and render the array, or tighten the filter until one row is possible.

How to check it worked

  • The empty state renders when the row is missing, instead of a 406.
  • A filter that should match one row returns that object, and a filter that matches many does not call .single().

Sources

More Supabase RLS and permissions fixes

Keep going on your own.

The guides stay free. A deep leak report is $15. Fix packs are $24, or $49 for all three. There is no done-for-you repair.

See products