Deine Query sieht richtig aus – und trotzdem wirft der Supabase-JS-Client:
JSON object requested, multiple (or no) rows returned
code: PGRST116
Das kommt fast immer von .single() (oder falsch genutztem .maybeSingle()), wenn PostgREST nicht genau eine Zeile bekommt. So behebst du es sauber.
Das Problem: .single() heißt genau eine Zeile
.single() sagt PostgREST: gib ein JSON-Objekt zurück. Ist das Ergebnis leer oder hat mehr als eine Zeile, kommt PGRST116 statt Daten.
Häufige Ursachen:
- Keine passende Zeile (Filter zu streng, falsche ID, RLS hat die Zeile versteckt)
- Mehrere Zeilen passen (kein eindeutiger Filter)
.single()versehentlich auf einer Listen-Abfrage
Leere Ergebnisse unter RLS fühlen sich oft wie „Zeile fehlt“ an – Policies und auth.uid() prüfen. Bei Insert-RLS-Fehlern: new row violates row-level security policy.
Die Lösung: Erwartung klar wählen
Schritt 1: maybeSingle, wenn 0 Zeilen ok sind
const { data, error } = await supabase
.from('profiles')
.select('id, display_name')
.eq('id', userId)
.maybeSingle()
if (error) {
console.error(error.code, error.message)
return
}
if (!data) {
// noch kein Profil – anlegen oder Onboarding zeigen
}
maybeSingle() liefert null bei 0 Zeilen und fehlerhaft weiter, wenn mehrere Zeilen passen.
Schritt 2: .single() nur bei garantiert eindeutigen Zeilen
// OK, wenn id Primary Key ist und die Zeile existieren muss
const { data, error } = await supabase
.from('profiles')
.select('*')
.eq('id', session.user.id)
.single()
Wenn die Zeile noch fehlen darf: lieber maybeSingle() oder PGRST116 bewusst behandeln.
Schritt 3: Filter schärfen bei mehreren Treffern
// Zu lose → mehrere Zeilen → PGRST116
await supabase.from('orders').select('*').eq('user_id', userId).single()
// Besser: eindeutiger Key
await supabase
.from('orders')
.select('*')
.eq('id', orderId)
.eq('user_id', userId)
.maybeSingle()
Schritt 4: „Keine Zeile“ von echten Fehlern trennen
const { data, error } = await supabase
.from('profiles')
.select('*')
.eq('id', userId)
.maybeSingle()
if (error) throw error
if (!data) {
await supabase.from('profiles').insert({ id: userId })
}
Häufige Fehler
- PGRST116 als Netzwerkfehler behandeln: es ist ein Result-Shape-Mismatch.
- Annehmen die Zeile fehlt, obwohl RLS SELECT blockiert: siehe auch permission denied for table.
- .single() nach Insert ohne SELECT-Policy: verwandt mit dem klassischen RLS-Insert-Fehler beim Return.
Checkliste
- ✅ Sind 0 Zeilen ein gültiges Ergebnis? →
maybeSingle() - ✅ Filter eindeutig genug (Primary/Unique Key)?
- ✅ RLS SELECT-Policy erlaubt die Zeile für diesen User?
- ✅ Kein versehentliches
.single()auf 1:n-Relationen?
Fazit
PGRST116 heißt: PostgREST hat für eine Singular-Antwort nicht genau eine Zeile bekommen. maybeSingle() wenn Fehlen normal ist, Filter schärfen bei Mehrfachtreffern, RLS prüfen wenn „fehlende“ Zeilen sichtbar sein sollten.
Verwandte Artikel
- RLS beheben: new row violates row-level security policy
- permission denied for table (42501) beheben
- How to query users table?
- Supabase Auth: Invalid login credentials
- infinite recursion detected in policy beheben
Siehst du weiter PGRST116? Query-Form (Tabelle + Filter, ohne Secrets) in einen Kommentar.
Kommentare