Zum Inhalt springen

Sicherheitsgrundlagen

"Row-level security policy for table objects" beim Upload

"New row violates row-level security policy for table objects" heißt: Deinem Upload fehlt eine insert-Regel. Ein öffentlicher Bucket fügt keine hinzu.

Vlad Tkachenko9 Min. Lesezeit
Eine verriegelte Annahmeklappe mit einem Dokument davor, dahinter ein Regal voller Dateien mit einem Deckel über der Oberkante.

Kurz gesagt

  • "New row violates row-level security policy for table objects" heißt, dass dein Upload bei Supabase Storage angekommen ist und keine Regel auf storage.objects ihn hineingelassen hat. Die Datei wurde nicht gespeichert, und der Rest des Buckets ist unberührt.
  • Storage hält seine Regeln für jeden Bucket deines Projekts auf einer einzigen Tabelle, und darum nennt die Meldung eine Tabelle, die du nie angelegt hast.
  • Den Bucket öffentlich zu machen behebt es nicht. Supabase prüft Uploads so oder so, und öffentlich entscheidet nur, wer eine Datei öffnen darf, deren Adresse er schon hat.
  • Ein Upload braucht eine insert-Regel auf storage.objects. Wenn dein Code mit upsert speichert, braucht er zusätzlich select und update.

Deine App lädt eine Datei hoch. In der Vorschau deines Builders ging es, oder letzte Woche ging es, und jetzt kommt bei jedem Versuch ein Satz über Row Level Security zurück:

new row violates row-level security policy for table "objects"

Das meiste an diesem Satz kommt dir bekannt vor, wenn du das schon einmal auf einer eigenen Tabelle durchgemacht hast. Anders ist das letzte Wort, denn objects ist keine Tabelle, die du angelegt hast.

Das ist der Punkt, den Anleitung für Anleitung falsch darstellt: Die erste Lösung, die du finden wirst, ist, den Bucket öffentlich zu machen, und sie tut für Uploads nichts. Supabases eigene Dokumentation sagt genau das in einer Zeile. Dieser Schalter lässt den Upload abgelehnt und öffnet die Dateien, die ohnehin schon drin lagen.

Was "new row violates row-level security policy for table objects" bedeutet

Dein Upload ist bei Supabase Storage angekommen, Storage hat die Regeln auf einer Tabelle namens storage.objects gefragt, ob diese Datei hinein darf, keine gefunden, die ja sagt, und abgelehnt.

Die Zeile in der Meldung gibt es wirklich. Storage hält für jede Datei genau eine Zeile in storage.objects, mit dem Namen der Datei, dem Bucket, in dem sie liegt, und wer sie abgelegt hat. Eine Datei zu schreiben heißt, diese Zeile zu schreiben, also entscheiden die Regeln auf dieser Tabelle, ob der Upload überhaupt stattfindet. Verloren ist nichts: Es wurde keine Datei gespeichert, und der Rest des Buckets liegt genau so da wie vor einer Minute.

Die Formulierung kommt von Postgres, der Datenbank unter Supabase, und deshalb liest sie sich wie Maschinerie. Sie trägt den Code 42501, denselben Code wie ein abgelehntes Speichern in einer deiner eigenen Tabellen.

Warum die Meldung "objects" nennt und nicht deinen Bucket

Weil Storage die Regeln für jeden Bucket deines Projekts auf dieser einen Tabelle hält.

Ein Bucket ordnet Dateien. Eigene Regeln hat er nicht, und es hängt auch kein Policy-Editor an ihm. storage.objects ist der Ort, an dem die Regeln liegen, für alle deine Buckets zugleich, und bucket_id ist eine Spalte darauf. Eine Regel, die "nur im Bucket avatars" sagt, wird also als Bedingung auf dieser Spalte geschrieben.

Das ist auch der Grund, warum die Tabellenregel von letzter Woche nicht geholfen hat. Eine Regel auf profiles ist eine Regel über Zeilen in profiles, und eine Datei ist eine Zeile in storage.objects.

Jeder Bucket deines Projekts wird von derselben Tabelle regiert. Die Regeln auf deinen eigenen Tabellen stehen jenseits dieser Trennlinie und treffen nie auf eine Datei.

Muss ich den Bucket öffentlich machen, damit der Upload geht?

Nein. Hinter einem Bucket stecken zwei verschiedene Fragen, und der Schalter beantwortet nur eine davon. Wer eine Datei herausholen darf, entscheidet öffentlich. Wer eine Datei hineinlegen darf, ist das Thema deiner Fehlermeldung, und Supabases Dokumentation ist eindeutig, dass die Einstellung dort nicht hinreicht. Von der Seite über die zwei Arten von Bucket, gelesen am 11. Oktober 2026:

Die Zugriffskontrolle gilt weiterhin für andere Arten von Vorgängen, einschließlich Hochladen, Löschen, Verschieben und Kopieren.

Was öffentlich tatsächlich tut, steht auf derselben Seite genauso klar: Wer die Adresse einer Datei hat, kann sie ohne Anmeldung öffnen. Mehr ist die Einstellung nicht.

Umlegen bringt dich also in den einen Zustand, den niemand will. Der Upload wird weiter abgelehnt, weil Hochladen nie das war, was die Einstellung steuerte, und die Dateien, die schon im Bucket lagen, lassen sich jetzt von jedem öffnen, der ihre Adressen hat. Was ein öffentlicher Bucket dich wirklich kostet, ist eine andere Frage als dieser Fehler und lohnt sich, bevor du den Schalter anfasst.

Was ein Bucket beim Upload wirklich prüft

Eine Regel, und sie heißt insert.

Supabases Seite zur Zugriffskontrolle nennt den Standard klar: Storage erlaubt ohne Policies keine Uploads in Buckets, und du erlaubst Vorgänge gezielt, indem du sie auf storage.objects schreibst. Dann benennt sie die, die du brauchst:

Die einzige RLS-Policy, die zum Hochladen von Objekten nötig ist, ist beispielsweise, die Berechtigung INSERT auf der Tabelle storage.objects zu erteilen.

Dazu gibt es eine zweite Hälfte, und sie ist der häufigste Grund, warum eine insert-Regel den Fehler nicht abstellt:

Um das Überschreiben von Dateien über die upsert-Funktion zu erlauben, musst du zusätzlich die Berechtigungen SELECT und UPDATE erteilen.

Wenn dein Upload upsert: true mitschickt, was Storage auffordert, eine Datei gleichen Namens zu ersetzen, falls schon eine da ist, dann reicht eine insert-Regel allein nicht. Eine Datei zu ersetzen sind drei Fragen statt einer: Darfst du diese Zeile anlegen, darfst du die vorhandene sehen, und darfst du sie ändern.

Was deine App von Storage willWas sie auf storage.objects braucht
eine neue Datei hochladeneine insert-Regel
eine Datei gleichen Namens ersetzen (upsert)insert, dazu select und update
eine Datei in einem privaten Bucket öffneneine select-Regel
auflisten, was in einem Bucket liegteine select-Regel
eine Datei löscheneine delete-Regel

Du musst nicht alle fünf schreiben. Schreib die, die deine App tatsächlich tut, bei den meisten Uploads also die erste Zeile und manchmal die zweite.

Ein Lager, zwei Öffnungen. Der Schalter hängt an der unteren. Ein Upload kommt an der oberen an, wo eine Regel, die noch niemand geschrieben hat, über den Einlass entscheidet.

Die Regel, die deine App hochladen lässt, und nur deine App

Nenne den Bucket, und sag, für wen die Regel gilt.

Der Ausgangspunkt der Dokumentation beschränkt einen Upload auf einen Bucket und auf angemeldete Besucher:

create policy "Allow authenticated uploads"
on storage.objects
for insert
to authenticated
with check (bucket_id = 'my_bucket_id');

to authenticated ist der Teil, den du nicht überspringen solltest. Er bedeutet, dass die Regel für angemeldete Besucher gilt; lass ihn weg, und sie gilt für alle, Fremde eingeschlossen.

Für alles, was einer bestimmten Person gehört, legt die von Supabase veröffentlichte Fassung die Dateien jeder Person in einen nach ihr benannten Ordner:

create policy "Allow authenticated uploads"
on storage.objects
for insert
to authenticated
with check (
  bucket_id = 'my_bucket_id' and
  (storage.foldername(name))[1] = (select auth.jwt()->>'sub')
);

storage.foldername(name) zerlegt den Pfad einer gespeicherten Datei in ihre Ordner, [1] ist also der erste davon. auth.jwt()->>'sub' ist die Id desjenigen, der angemeldet ist und die Anfrage stellt. Zusammen gelesen sagen die zwei Zeilen, dass du eine Datei in den nach dir benannten Ordner legen darfst, in diesem Bucket, und sonst nirgends.

Beides sind Supabases Beispiele und nicht unsere, gelesen am 11. Oktober 2026, mit my_bucket_id genau dort, wo sie es gelassen haben, damit du siehst, welcher Teil der Name deines eigenen Buckets ist.

Wenn du das Ergebnis lieber von außen sehen willst: Unser kostenloser Scan fragt dein Live-Projekt, welche deiner Buckets ihren Inhalt an einen Fremden herausgeben. Er dauert etwa 20 Sekunden und braucht kein Konto: Scanne deine App.

Was eine Leseregel ungefragt mit herausgibt

Einen Bucket aufzulisten und daraus herunterzuladen ist dasselbe Recht, also macht eine Regel, die deine Downloads zum Laufen bringt, auch den Inhalt des Buckets auflistbar.

Supabases Seite zu den Hilfsfunktionen sagt es direkt: Ein einzelnes SQL-Recht wie SELECT wird von mehreren Storage-Aktionen benutzt. Die Seite zur Zugriffskontrolle warnt dann vor dem konkreten Fall, unter einem Beispiel, das einen Bucket mit Avataren für alle öffnet:

Der Filter allow_any_operation() ist hier entscheidend, denn ohne ihn könnten Benutzer den Inhalt des Buckets auflisten.

Das ist die Lücke, die wir von außen messen. Wir haben 8.435 lebende Apps gescannt, die ein Supabase-Projekt nennen. Bei 4.703 davon hat die Bucket-Prüfung eine Antwort bekommen, und 792 von diesen haben auf unsere Auflistungsanfrage mit den Namen dessen geantwortet, was darin lag, ohne dass jemand angemeldet war. Das ist etwa jede sechste der Apps, die wir fragen konnten.

Ein Name reicht oft schon, denn ein Bucket, der auflistet, erspart einem Fremden das Raten von Dateinamen. invoice-2026-03-hannah.pdf sagt, wem die Datei gehört, bevor sie jemand öffnet.

Die Lösung, die Supabase dokumentiert, ist zu sagen, für welche Storage-Aktion die Regel gilt:

create policy "Allow users to list their own objects"
on storage.objects
for select
to authenticated
using (
  storage.allow_only_operation('object.list')
  and owner_id = (select auth.uid()::text)
);

storage.allow_only_operation und die Schwesterfunktion storage.allow_any_operation sind die Art, wie eine select-Regel sich auf eine der Aktionen verengt, die sich das Recht teilen. Ohne eine von beiden ist eine Regel, die du geschrieben hast, damit deine App ein Bild zeigen kann, auch eine Regel, die alles im Bucket vorliest.

Eine Regel, zwei verschiedene Storage-Aktionen. Die Platte auf dem unteren Weg ist der Aktionsfilter, und die Striche sind, wie es aussieht, wenn niemand einen geschrieben hat.

Ob ein auflistbarer Bucket für deine App ein Problem ist, hängt davon ab, was drin liegt, und das kann dir ein Scanergebnis nicht beantworten.

Wann öffentlich die richtige Antwort ist

Wenn die Dateien von jedem gesehen werden sollen, der fragt, und das ist eine echte Kategorie, zu der Supabase eigene Beispiele nennt.

Supabases eigene Beispielfälle für einen öffentlichen Bucket sind Profilbilder, öffentliche Medien und Inhalte von Blogbeiträgen. Das sind Dateien, die deine App einem nicht angemeldeten Besucher zeigt, und sie aus einem öffentlichen Bucket auszuliefern ist außerdem schneller, weil die zwei Arten von Bucket unterschiedlich zwischengespeichert werden.

Für die andere Art nennt die Dokumentation zwei Wege, eine Datei aus einem privaten Bucket zu bekommen: ein Download mit dem Token der angemeldeten Person, oder ein signierter Link, der eine begrenzte Zeit funktioniert. Beide lassen die Entscheidung bei deinen Regeln statt bei dem, der die Adresse gefunden hat.

Wie der Bucket nach heute richtig bleibt

Nach korrekten Regeln bewegen sich zwei Dinge: Jemand legt den Schalter um, während er einem ganz anderen Fehler nachgeht, und eine Datei verschwindet.

Reeve Monitor führt die neun Prüfungen von außen für dich erneut aus:

  • alle neun Prüfungen jede Stunde, auf bis zu drei Apps, die Bucket-Auflistung eingeschlossen
  • ob die App erreichbar ist, alle 60 Sekunden
  • eine Nachricht, wenn sich ein Ergebnis ändert, damit ein Bucket, der heute Nacht aufgegangen ist, nicht wartet, bis du hinschaust
  • ein Monatsbericht über das Gesehene

Reeve Care hält eine Kopie von dem, was drin liegt:

  • jede Nacht eine verschlüsselte Kopie deiner Supabase-Datenbank, dort abgelegt, wo dein Projekt nicht hinreicht
  • jede Kopie geprüft, bevor sie zählt, durch Zählen der Zeilen in jeder Tabelle
  • auch deine hochgeladenen Dateien, sobald du einen Storage-Zugang verbindest
  • eine Wiederherstellung auf Knopfdruck, wenn du sie brauchst
  • alles, was Monitor tut

Beide stehen auf der Preisseite, die manchmal unter der Listenangabe hier liegt und nie darüber.

Was heute zu tun ist

Was zu tun ist

  • Lies die Meldung als Ablehnung. Die Datei wurde nicht gespeichert, der Bucket ist unverändert, und es ist nichts wiederherzustellen.
  • Leg eine insert-Regel auf storage.objects an, die deinen Bucket in bucket_id nennt und die TO-Klausel trägt, die du gemeint hast.
  • Wenn dein Upload upsert: true mitschickt, nimm select und update dazu, sonst stellt die insert-Regel allein den Fehler nicht ab.
  • Lass den Öffentlich-Schalter dabei in Ruhe. Über Uploads hat er nichts zu sagen, und darüber, wer das schon Gespeicherte öffnen kann, hat er sehr wohl etwas zu sagen.
  • Lies jede select-Regel auf storage.objects und frag, was sie außer dem Download erlaubt, für den du sie geschrieben hast. Das Auflisten teilt sich dieses Recht.

Fang mit dem Bucket an, aus dem der Fehler kam, und sieh dir dann die anderen Buckets im selben Projekt an, denn eine einmal breit geschriebene Regel ist meistens zweimal eingefügt worden. Die 10-Minuten-Sicherheitscheckliste deckt ab, was in einer frisch gestarteten App sonst offen bleibt, und der Supabase-Sicherheitsleitfaden geht den Rest dessen durch, was ein Fremder erreichen kann.

FAQ

Warum scheitert mein Supabase-Upload an einem Row-Level-Security-Fehler?

Weil Supabase Storage die Regeln auf einer Tabelle namens storage.objects gefragt hat, ob deine Datei hinein darf, und keine Regel gefunden hat, die ja sagt. Storage schreibt für jede Datei, die es hält, genau eine Zeile in diese Tabelle, und Row Level Security gilt für diese Zeile genauso wie für eine Zeile in jeder anderen Tabelle. Es wurde keine Datei gespeichert, und an dem, was schon im Bucket lag, hat sich nichts geändert. Die Meldung trägt den Postgres-Code 42501, denselben Code wie beim abgelehnten Speichern in einer eigenen Tabelle.

Muss ich meinen Bucket öffentlich machen, damit der Upload geht?

Nein, und es hilft auch nicht. Supabase dokumentiert, dass die Zugriffskontrolle für Hochladen, Löschen, Verschieben und Kopieren weiterhin gilt, egal auf welcher Einstellung der Bucket steht. Öffentlich ändert eine einzige Sache: ob jemand mit einer Dateiadresse diese Datei ohne Anmeldung öffnen kann. Der Schalter lässt deinen Upload also abgelehnt und macht die Dateien, die schon drin liegen, für jeden mit ihrer Adresse lesbar.

Welche Policies braucht ein Bucket?

Ein Upload braucht eine insert-Regel auf storage.objects. Wenn dein Code Dateien gleichen Namens ersetzt, also upsert benutzt, braucht er laut Supabase zusätzlich select und update. Eine Datei aus einem privaten Bucket zu öffnen braucht eine select-Regel, und das Auflisten des Bucket-Inhalts ebenso, weil diese beiden Storage-Aktionen auf demselben SQL-Recht laufen. Löschen braucht eine delete-Regel. Du musst nicht alle vier schreiben, nur die, die deine App tatsächlich ausführt.

Ist ein öffentlicher Bucket gefährlich?

Das hängt ganz davon ab, was drin liegt. Öffentlich ist die richtige Einstellung für Profilbilder, Logos und alles andere, was deine App einem nicht angemeldeten Besucher zeigt, und genau das führt Supabase als eigene Beispielfälle auf. Für Rechnungen, Exporte oder irgendetwas, das einer bestimmten Person gehört, ist sie falsch, und dafür willst du einen privaten Bucket mit einem signierten Link. Die Frage war nie, ob öffentlich schlecht ist.

Wie prüfe ich, ob mein Bucket auflistbar ist?

Frag ihn von außen, ohne angemeldetes Konto, genau so wie ein Fremder es täte. Das Auflisten wird von einer select-Regel erlaubt und nicht vom Öffentlich-Schalter, deshalb beantwortet weder der Schalter im Dashboard noch ein Blick auf deine Policy-Liste diese Frage. Unser kostenloser Scan macht das auf deinem Live-Projekt und sagt dir, welche deiner Buckets mit den Namen ihres Inhalts geantwortet haben.

Geschrieben von

Vlad Tkachenko

Gründer, Reeve

Ich schaue mir den ganzen Tag Apps an, die mit Lovable, Bolt, v0, Cursor und Replit gebaut wurden, und die kurze Liste von Fehlern, die darin immer wieder auftauchen.

Mehr über den Autor

Weiterlesen

Alle Artikel

Unsicher, wie es um deine eigene App steht?

Starte einen kostenlosen Scan und erhalte in rund 20 Sekunden eine verständliche Note von A bis F. Ohne Konto, ohne Karte.

App kostenlos scannen

Automatisierte externe Prüfung, kein vollständiges Audit. Das Fehlen von Funden ist keine Garantie für Sicherheit.