[{"data":1,"prerenderedAt":1043},["ShallowReactive",2],{"blog-de-supabase-single-row-error":3,"blog-index-de":512},{"id":4,"title":5,"body":6,"category":469,"cover":470,"coverAlt":471,"description":472,"draft":473,"extension":474,"faq":475,"image":491,"keywords":492,"meta":500,"navigation":501,"ogTitle":502,"path":503,"published":504,"seo":505,"stem":506,"tldr":507,"updated":504,"__hash__":511},"blog_de\u002Fblog\u002Fsupabase-single-row-error.md","Supabase \"multiple (or no) rows returned\" heißt meist: keine Zeilen",{"type":7,"value":8,"toc":455},"minimark",[9,13,16,27,43,48,51,54,61,65,72,96,102,111,137,141,147,165,175,178,182,185,194,197,203,206,213,217,220,251,254,262,266,271,274,280,286,290,293,296,299,303,311,316,332,337,345,349,355,364,379,389,406,410,442],[10,11,12],"p",{},"Jemand bekommt von deiner App gesagt, ein Datensatz sei nicht zu finden. Du\nöffnest den Supabase Table Editor, und der Datensatz liegt genau dort, in der\nTabelle, mit der richtigen id.",[10,14,15],{},"Aus der Datenbank kam das hier zurück:",[17,18,23],"pre",{"className":19,"code":21,"language":22},[20],"language-text","{\n  \"code\": \"PGRST116\",\n  \"message\": \"JSON object requested, multiple (or no) rows returned\",\n  \"details\": \"Results contain 0 rows, application\u002Fvnd.pgrst.object+json requires 1 row\"\n}\n","text",[24,25,21],"code",{"__ignoreMap":26},"",[10,28,29,30,34,35,38,39,42],{},"Und hier ist der Teil, den eine Anleitung nach der anderen falsch macht: ",[31,32,33],"strong",{},"null\nZeilen ist eine Antwort, die deine eigenen Regeln erzeugen können, und sie liest\nsich genau wie verschwundene Daten."," Such diese Meldung, und man sagt dir, du\nsollst ",[24,36,37],{},".single()"," durch ",[24,40,41],{},".maybeSingle()"," ersetzen. Das beendet den Fehler\ntatsächlich. Es sagt dir nichts darüber, ob die Zeile fehlte oder ob dein\nBesucher sie nie sehen durfte, und diese beiden Fälle werden unterschiedlich\nrepariert.",[44,45,47],"h2",{"id":46},"was-heißt-json-object-requested-multiple-or-no-rows-returned","Was heißt \"JSON object requested, multiple (or no) rows returned\"?",[10,49,50],{},"Deine Abfrage hat die Datenbank nach genau einer Zeile gefragt, und das Ergebnis\nenthielt eine andere Zahl. Fast immer ist diese Zahl null.",[10,52,53],{},"Stell dir einen Lesesaal vor, in dem du einen Zettel ausfüllst und jemand hinter\ndem Tresen das Buch holt. Auf deinem Zettel steht: bring mir das eine Buch mit\ndieser Nummer. Der Tresen kommt zurück und sagt dir, zu diesem Zettel gebe es\nnichts. Das ist die einzige Antwort, die der Tresen gibt, und sie ist dieselbe,\nob das Buch nie im Katalog stand oder ob es in einem Regal liegt, für das du\nkeine Freigabe hast. Niemand hält dir etwas vor. Das Zettelsystem wurde so\ngebaut, dass alles, wofür du keine Freigabe hast, in deiner Sicht auf den Katalog\nschlicht nicht vorkommt.",[10,55,56,57,60],{},"Deine App ist diejenige, die den Zettel hält, und die Zahl, mit der der Tresen\nzurückkam, steht in der ",[24,58,59],{},"details","-Zeile der Antwort.",[44,62,64],{"id":63},"zwei-verschiedene-meldungen-und-derselbe-fehlercode","Zwei verschiedene Meldungen, und derselbe Fehlercode",[10,66,67,68,71],{},"Der Code steht fest, der Satz nicht, also geh nach ",[24,69,70],{},"PGRST116",".",[10,73,74,75,78,79,81,82,85,86,89,90,92,93,71],{},"Für diesen einen Fehler sind zwei Formulierungen im Umlauf, und welche du siehst,\nhängt davon ab, welche Version von PostgREST dein Projekt fährt. PostgREST ist\nder Server, der deine Supabase-Tabellen in die HTTP-API verwandelt, mit der deine\nApp spricht. Seine Dokumentation zu Version 12 nennt die Meldung\n",[24,76,77],{},"JSON object requested, multiple (or no) rows returned",", mit einer\n",[24,80,59],{},"-Zeile, die\n",[24,83,84],{},"Results contain 0 rows, application\u002Fvnd.pgrst.object+json requires 1 row","\nlautet. In den Versionen 13 und 14 ist dieselbe Lage als\n",[24,87,88],{},"Cannot coerce the result to a single JSON object"," dokumentiert, mit ",[24,91,59],{}," als\n",[24,94,95],{},"The result contains 0 rows",[10,97,98,99,101],{},"Der ältere Satz hat ein zweites Leben jenseits alter Projekte. Rufst du\n",[24,100,41],{}," auf und passt mehr als eine Zeile, schreibt der JavaScript-Client\nvon Supabase den Fehler selbst, statt einen vom Server weiterzureichen, und die\nMeldung, die er schreibt, ist die ältere Formulierung. Der erste Satz kommt also\nimmer noch in Apps an, deren Datenbank den zweiten geschickt hätte.",[10,103,104,105,107,108,110],{},"Was sich nicht bewegt, ist der Code. PostgRESTs Fehlertabelle führt ",[24,106,70],{}," in\nallen drei Versionen unter 406, mit derselben Beschreibung: mehr als eine Zeile\noder keine, wenn genau eine verlangt wurde. Lies das Feld ",[24,109,24],{}," und ignorier den\nFließtext.",[112,113,115],"callout",{"type":114},"warn",[10,116,117,120,121,124,125,128,129,132,133,136],{},[31,118,119],{},"Wenn du die Meldung in deinem eigenen Code als Zeichenkette vergleichst,\nvergleich stattdessen den Code."," Ein ",[24,122,123],{},"catch","-Block, der ",[24,126,127],{},"error.message"," gegen\n",[24,130,131],{},"'JSON object requested, multiple (or no) rows returned'"," prüft, funktioniert\nheute und hört an dem Tag auf, an dem dein Projekt auf ein neueres PostgREST\nwechselt, ohne ein Deploy von dir dazwischen. ",[24,134,135],{},"error.code === 'PGRST116'","\nübersteht das.",[44,138,140],{"id":139},"warum-single-das-überhaupt-erzeugt","Warum .single() das überhaupt erzeugt",[10,142,143,144,146],{},"Weil ",[24,145,37],{}," eine Anweisung über die Form der Antwort ist und kein Filter auf\nden Daten.",[10,148,149,150,152,153,156,157,160,161,164],{},"Schreibst du ",[24,151,37],{},", fügt der Supabase-Client der Anfrage einen Header\nhinzu: ",[24,154,155],{},"Accept: application\u002Fvnd.pgrst.object+json",". Dieser Header bittet die\nDatenbank, die Zeile für sich zu schicken, als Datensatz. Er ist es, der deinem\nCode erlaubt, ",[24,158,159],{},"data.name"," zu schreiben, wo sonst ",[24,162,163],{},"data[0].name"," stehen müsste.",[10,166,167,168,170,171,174],{},"Die Datenbank hält sich strikt daran. Eine Zeile geht als Datensatz zurück. Jede\nandere Zahl von Zeilen lässt sich in dieser Form gar nicht schicken, also ist die\nAntwort ein 406 und ein Fehlerobjekt. Lass das ",[24,169,37],{}," weg, und dieselbe\nAbfrage gibt ",[24,172,173],{},"[]"," mit einem 200 zurück, ohne Fehler.",[10,176,177],{},"Es musste also nichts kaputtgehen, damit das hier entsteht. Ein leeres Ergebnis\nwurde zu einem Fehler, weil deine Abfrage sagte, die Antwort müsse genau einen\nDatensatz enthalten.",[44,179,181],{"id":180},"ursache-1-die-zeile-ist-da-und-deine-regeln-sagen-nein","Ursache 1: die Zeile ist da, und deine Regeln sagen nein",[10,183,184],{},"Row Level Security lehnt deine Abfrage nicht ab. Sie nimmt Zeilen heraus, und\neine herausgenommene Zeile war nie im Ergebnis, das gezählt wird.",[10,186,187,188,190,191,193],{},"Row Level Security ist der Satz an Regeln auf jeder Supabase-Tabelle, der Zeile\nfür Zeile entscheidet, welche Zeilen ein bestimmter Besucher lesen darf. Erlaubt\nkeine Regel deinem Besucher, die Zeile zu lesen, die deine Abfrage genannt hat,\nwird diese Zeile entfernt, bevor das Ergebnis gemessen wird. Die Zahl ist null.\nDein ",[24,189,37],{}," wollte eins. Du bekommst ",[24,192,70],{},", und kein Teil der Antwort\nerwähnt, dass eine Regel beteiligt war.",[10,195,196],{},"Das ist wieder der Lesesaal, und darum sagt der Tresen zweimal dasselbe. Deine\nFreigabe wird angewendet, bevor das Regal überhaupt durchsucht wird, also\nerzeugen ein Buch, das du nicht ausleihen darfst, und ein Buch, das es nicht\ngibt, einen identischen Zettel, der zurückkommt.",[198,199],"diagram",{"alt":200,"caption":201,"src":202},"Eine Anforderung kommt von links und teilt sich in zwei Bahnen. In der oberen Bahn trägt ein Regal eine teal gezeichnete Zeile, und die Bahn wird von einem bernsteinfarbenen Gitter gestoppt, bevor sie das Regal erreicht. In der unteren Bahn ist das Regal leer und gestrichelt gezeichnet. Beide Bahnen enden an derselben leeren Ablage, die mit einer Null markiert ist.","Eine von deinen Regeln versteckte Zeile und eine Zeile, die es nicht gibt, lassen das Ergebnis beide leer. Die Antwort zählt Zeilen, also kommen die beiden als derselbe Fehler an.","\u002Fblog\u002Fsupabase-single-row-error\u002Ftwo-reasons-one-answer-1600x700.png",[10,204,205],{},"Deshalb führt dich auch der Table Editor in die Irre. Der SQL Editor und der\nTable Editor in deiner Supabase-Konsole laufen mit Rechten, für die deine\nPolicies nicht gelten, also zeigen sie dir jede Zeile. Die Anfrage deiner App\nträgt deinen Publishable Key und die Sitzung deines Besuchers, und für sie gelten\ndie Policies. Zwei Sichten auf eine Tabelle, und nur eine davon ist die, die\ndeine Nutzerinnen und Nutzer bekommen.",[10,207,208,209,212],{},"Diesen Unterschied sieht man von außen, und genau deshalb können wir ihn zählen.\nUnser Scanner liest Live-Apps so, wie es ein Fremder täte. Hinter 8.435 der Apps,\ndie er benotet hat, steckt ein Supabase-Projekt. Bei 3.680 davon hat die Frage\n\"kann jemand ohne Konto diese Tabelle lesen\" überhaupt eine brauchbare Antwort\nbekommen, und ",[31,210,211],{},"1.584 davon haben mit Nein geantwortet",": ein Fremder, der nach\nden Zeilen fragte, bekam nichts zurück. Dieses Nichts ist dasselbe Nichts, das\ndeine eigene App bekommt, wenn keine Policy auf sie passt.",[44,214,216],{"id":215},"wie-du-eine-versteckte-zeile-von-einer-fehlenden-unterscheidest","Wie du eine versteckte Zeile von einer fehlenden unterscheidest",[10,218,219],{},"Setz dieselbe Suche zweimal ab, einmal dort, wo die Policies gelten, und einmal\ndort, wo sie es nicht tun. Eine Abfrage klärt es.",[221,222,223,239,245],"ol",{},[224,225,226,227,230,231,234,235,238],"li",{},"Öffne deine Supabase-Konsole, geh in den ",[31,228,229],{},"SQL Editor"," und hol die Zeile über\ndenselben Wert, den deine App benutzt hat:\n",[24,232,233],{},"select * from your_table where id = 'the-id-your-app-sent';",". Eine Abfrage\naus dem SQL Editor läuft über die Rolle ",[24,236,237],{},"postgres",", für die deine Policies\nnicht gelten.",[224,240,241,244],{},[31,242,243],{},"Kommt die Zeile zurück",", dann gibt es sie, und irgendetwas zwischen deiner\nApp und der Zeile hat sie entfernt. Dieses Etwas ist eine Policy, und du bist\nbei Ursache 1. Lies die Policies auf dieser Tabelle.",[224,246,247,250],{},[31,248,249],{},"Kommt auch dort nichts zurück",", fehlt die Zeile wirklich, und du bist bei\nUrsache 3 weiter unten. Mit deinen Regeln ist nichts verkehrt.",[10,252,253],{},"Mach das, bevor du eine Zeile Code änderst. Beide Ursachen erzeugen dasselbe\nFehlerobjekt, und die beiden Reparaturen haben nichts gemeinsam.",[10,255,256,257,71],{},"Wenn du ohnehin gerade die Policies auf dieser Tabelle anschaust, lohnt es sich\nzu wissen, was sie jemandem ganz ohne Konto sagen. Unser kostenloser Scan liest\ndeine Live-App und sagt dir, welche deiner Tabellen einem Fremden antworten. Er\ndauert etwa 20 Sekunden und braucht kein Konto:\n",[258,259,261],"a",{"href":260},"\u002Fsecurity-scanner","App scannen",[44,263,265],{"id":264},"ursache-2-es-kamen-mehrere-zeilen-zurück","Ursache 2: es kamen mehrere Zeilen zurück",[10,267,268,270],{},[24,269,37],{}," wurde auf eine Suche angewendet, die mehr als eine Zeile treffen\nkann.",[10,272,273],{},"Eine Suche über einen Primärschlüssel trifft per Definition eine Zeile oder\nkeine. Eine Suche über eine E-Mail, einen Slug, einen Namen, einen Status, einen\nFremdschlüssel: jede davon kann zwei treffen. Die übliche Vorgeschichte ist, dass\ndie Spalte in deinen Testdaten einen Wert pro Zeile hielt und damit aufhörte, als\nechte Menschen kamen.",[10,275,276,277,279],{},"Die Antwort sagt dir, bei welcher Ursache du bist. Beide Formulierungen der\n",[24,278,59],{},"-Zeile nennen die Zahl der Zeilen im Ergebnis. Null schickt dich zu\nUrsache 1 oder Ursache 3. Eine Zahl über null meint diese hier, und sie ist die\nAnzahl der Zeilen, die gepasst haben.",[10,281,282,283,285],{},"Die Reparatur ist nicht ",[24,284,41],{},". Das akzeptiert null Zeilen und meldet\nbei zwei weiterhin einen Fehler, ändert hier also nichts. Entweder schränkst du\ndie Abfrage über die Spalte, die wirklich eindeutig ist, auf eine Zeile ein, oder\ndu nimmst hin, dass es mehrere gibt, und liest eine Liste.",[44,287,289],{"id":288},"ursache-3-die-zeile-ist-wirklich-weg","Ursache 3: die Zeile ist wirklich weg",[10,291,292],{},"Manchmal fehlt die Zeile, und die Abfrage aus dem vorigen Abschnitt ist das, was\ndiesen Fall bestätigt.",[10,294,295],{},"Die gewöhnlichen Gründe, in der Reihenfolge, in der sie in einer vibe-codeten App\nauftauchen. Der Wert, nach dem deine Abfrage gefiltert hat, war leer, weil die id\nnoch nicht geladen war, als die Abfrage lief, also passte nichts. Die Zeile wurde\ngelöscht, von dir oder von einem Prompt, der mehr umgeschrieben hat als\nerwartet. Oder die Abfrage nennt eine Tabelle, die unter einem anderen Namen neu\ngebaut wurde, und die alten Zeilen gingen mit der alten Tabelle.",[10,297,298],{},"Nichts davon ist ein Sicherheitsproblem, und keines wird durch eine geänderte\nPolicy behoben. Findet der SQL Editor nichts, hör auf, über Row Level Security zu\nlesen, und schau dir an, was deine App übergibt.",[44,300,302],{"id":301},"single-oder-maybesingle-was-deine-abfrage-braucht","single oder maybeSingle: was deine Abfrage braucht",[10,304,305,307,308,310],{},[24,306,41],{},", wo nichts zu finden eine zulässige Antwort ist. ",[24,309,37],{},", wo\nes das nicht ist.",[10,312,313,315],{},[24,314,37],{}," behandelt jede Zahl von Zeilen außer eins als Fehler. Das ist das\nrichtige Verhalten für eine Suche über einen Primärschlüssel, wo null Zeilen\nheißt, dass es den Datensatz, um den es deinem Code geht, nicht gibt und\nWeitermachen schlimmer wäre als Anhalten.",[10,317,318,320,321,324,325,328,329,331],{},[24,319,41],{}," akzeptiert null Zeilen: es gibt dir ",[24,322,323],{},"data"," als ",[24,326,327],{},"null",", ohne\nFehler und mit einem 200. Mehr als eine Zeile ist weiterhin ein Fehler, mit\ndemselben Code ",[24,330,70],{},". Es passt also zu einer Profilzeile, die vielleicht noch\nnicht angelegt wurde, oder zu einem optionalen Datensatz, für den deine Seite\neinen leeren Zustand rendert.",[198,333],{"alt":334,"caption":335,"src":336},"Zwei Bahnen mit den Beschriftungen single und maybeSingle. Jede Bahn hat drei Felder, markiert mit 0, 1 und 2. In der single-Bahn ist das Feld 1 teal angenommen, und die Felder 0 und 2 tragen ein bernsteinfarbenes Kreuz. In der maybeSingle-Bahn sind die Felder 0 und 1 angenommen, und nur das Feld 2 ist gekreuzt.","Der einzige Unterschied liegt darin, was die beiden mit einem leeren Ergebnis machen. Zwei Zeilen lehnen beide ab, und keines von beiden ändert, was die Datenbank zurückgegeben hat.","\u002Fblog\u002Fsupabase-single-row-error\u002Fwhat-each-one-accepts-1600x640.png",[10,338,339,340,38,342,344],{},"Eine Sache, bei der du aufpassen musst. ",[24,341,37],{},[24,343,41],{}," zu\nersetzen ändert, wie deine App sich verhält, und ändert nichts an dem, was die\nDatenbank geschickt hat. Hat eine Policy die Zeile versteckt, hast du einen\nsichtbaren Fehler in eine Seite verwandelt, die so rendert, als gäbe es den\nDatensatz nicht, und zwar für genau die eine Person, die ihn sehen sollte. Der\nFehler hat dir etwas gesagt. Tausch erst nach dem Test oben, wenn du weißt, dass\nnull die ehrliche Antwort ist.",[44,346,348],{"id":347},"deine-regeln-im-blick-behalten-nachdem-du-sie-geändert-hast","Deine Regeln im Blick behalten, nachdem du sie geändert hast",[10,350,351,354],{},[31,352,353],{},"Eine Policy, die du aufmachst, um diesen Fehler loszuwerden, ist eine Änderung,\ndie von innen in deiner App niemand sieht."," Deine eigene Sitzung läuft weiter,\nder Fehler ist weg, und ob diese Tabelle jetzt einem Fremden antwortet, muss\njemand hingehen und nachfragen.",[10,356,357],{},[31,358,359,363],{},[258,360,362],{"href":361},"\u002Fwebsite-monitoring","Reeve Monitor"," fragt für dich nach:",[365,366,367,370,373,376],"ul",{},[224,368,369],{},"alle neun Checks jede Stunde, für bis zu drei Apps",[224,371,372],{},"eine E-Mail an dem Tag, an dem ein erneuter Scan deine App schlechter benotet als der vorige",[224,374,375],{},"ob die App erreichbar ist, alle 60 Sekunden",[224,377,378],{},"ein Monatsbericht über das Gesehene",[10,380,381],{},[31,382,383,384,388],{},"Eine Regel, die weit genug gelockert wird, um einen Fehler loszuwerden, kann\neinen Fremden Zeilen auch ändern lassen, nicht nur lesen.\n",[258,385,387],{"href":386},"\u002Fsupabase-backups","Reeve Care"," hält eine Kopie deiner Supabase-Datenbank dort,\nwo keine Änderung an deinen Regeln sie erreicht.",[365,390,391,394,397,400,403],{},[224,392,393],{},"eine verschlüsselte Kopie jeden Tag, außerhalb deines Supabase-Kontos aufbewahrt",[224,395,396],{},"jede Kopie geprüft, bevor sie zählt, durch Zählen der Zeilen in jeder Tabelle",[224,398,399],{},"eine Wiederherstellung per Klick, die sichert, was gerade da ist, bevor sie es ersetzt",[224,401,402],{},"deine hochgeladenen Dateien ebenso, sobald du einen Storage-Zugang verbindest",[224,404,405],{},"alles, was Monitor kann",[44,407,409],{"id":408},"was-heute-zu-tun-ist","Was heute zu tun ist",[411,412,413],"key-takeaways",{},[365,414,415,424,430,433,439],{},[224,416,417,418,420,421,423],{},"Geh nach dem Feld ",[24,419,24],{},". ",[24,422,70],{}," kommt unter zwei verschiedenen Sätzen an, und welchen du bekommst, hängt von der PostgREST-Version deines Projekts ab.",[224,425,426,427,429],{},"Lies die Zeilenzahl in der ",[24,428,59],{},"-Zeile. Null heißt leeres Ergebnis. Alles über null heißt, deine Suche hat mehrere Zeilen getroffen und braucht eine eindeutige Spalte.",[224,431,432],{},"Setz bei einem leeren Ergebnis dieselbe Suche im SQL Editor ab, bevor du Code änderst. Kommt die Zeile dort zurück und in deiner App nicht, hat eine Policy sie entfernt.",[224,434,435,436,438],{},"Wechsle zu ",[24,437,41],{},", sobald du weißt, dass null die ehrliche Antwort ist. Bei einer Zeile, die eine Policy versteckt, ersetzt es einen Fehler durch eine leere Seite, ohne Warnung.",[224,440,441],{},"Nachdem du eine Policy geändert hast, um das loszuwerden, prüf, was diese Tabelle jetzt jemandem ohne Konto zurückgibt.",[10,443,444,445,449,450,454],{},"Fang mit einer Abfrage im SQL Editor an, denn sie entscheidet, welche Hälfte\ndieses Artikels für dich gilt. Stellt sich heraus, dass eine Policy die Antwort\nwar, zeigt\n",[258,446,448],{"href":447},"\u002Fblog\u002Fenable-rls-on-every-supabase-table","Row Level Security für jede Tabelle anschalten",",\nwie man eine Regel schreibt, die die richtige Person durchlässt, und\n",[258,451,453],{"href":452},"\u002Fblog\u002Fnew-row-violates-row-level-security-policy","\"new row violates row-level security policy\"","\nist die Meldung, die du bekommst, wenn eine Policy ein Schreiben ablehnt, das du\nmit eigenen Augen siehst.",{"title":26,"searchDepth":456,"depth":456,"links":457},3,[458,460,461,462,463,464,465,466,467,468],{"id":46,"depth":459,"text":47},2,{"id":63,"depth":459,"text":64},{"id":139,"depth":459,"text":140},{"id":180,"depth":459,"text":181},{"id":215,"depth":459,"text":216},{"id":264,"depth":459,"text":265},{"id":288,"depth":459,"text":289},{"id":301,"depth":459,"text":302},{"id":347,"depth":459,"text":348},{"id":408,"depth":459,"text":409},"Sicherheitsgrundlagen","\u002Fblog\u002Fsupabase-single-row-error\u002Fcover-1200x630.png","Ein Anforderungszettel und eine leere Ablage an einem Tresen, dahinter ein Regal mit einer teal hervorgehobenen Zeile hinter einem bernsteinfarbenen Gitter.","Supabase gibt PGRST116 zurück, \"JSON object requested, multiple (or no) rows returned\", wenn die Abfrage nichts fand. Versteckte Zeilen wirken fehlend.",false,"md",[476,479,482,485,488],{"q":477,"a":478},"Was bedeutet PGRST116?","Es bedeutet, dass deine Abfrage die Datenbank nach genau einer Zeile gefragt hat und das Ergebnis eine andere Zahl enthielt. PostgREST, der Teil von Supabase, der deine App über HTTP bedient, gibt das als HTTP 406 mit dem Code PGRST116 zurück. Die Zahl steht in der details-Zeile der Antwort, und fast immer ist sie null.",{"q":480,"a":481},"Warum gibt meine Abfrage keine Zeile zurück, obwohl ich die Zeile in Supabase sehe?","Weil der SQL Editor in deiner Konsole mit Rechten läuft, für die deine Row-Level-Security-Policies nicht gelten, und deine App nicht. Erlaubt keine Policy deinem Besucher, diese Zeile zu lesen, wird sie aus seinem Ergebnis entfernt, bevor das Ergebnis gezählt wird, und zurück kommt eine Null. Die Zeile ist da. Sie war nie in der Antwort.",{"q":483,"a":484},"Was ist der Unterschied zwischen single und maybeSingle?","single() behandelt jede Zahl außer genau eins als Fehler. maybeSingle() akzeptiert null Zeilen und gibt dir data als null zurück, ohne Fehler, und meldet weiterhin einen Fehler, wenn mehr als eine Zeile passt. maybeSingle() passt also dort, wo nichts zu finden eine zulässige Antwort ist, etwa bei einem Profil, das es noch nicht gibt, und single() passt zu einer Suche über eine Spalte, die nur eine einzige Zeile treffen kann.",{"q":486,"a":487},"Löst Row Level Security diesen Fehler aus?","Das ist die häufigste Ursache in einer App, die mit Lovable, Bolt, Replit oder v0 gebaut wurde. Row Level Security filtert Zeilen aus einem Ergebnis heraus, statt die Anfrage abzulehnen, also ist eine Zeile, die niemand lesen darf, von einer Zeile, die es nicht gibt, nicht zu unterscheiden. Beide ergeben eine Null, und eine Abfrage, die genau eine Zeile verlangt, scheitert an beidem.",{"q":489,"a":490},"Warum ist es ein 406?","406 Not Acceptable ist der Status für eine Anfrage, die der Server nicht in der verlangten Form beantworten kann. Deine Abfrage trug einen Accept-Header, der sagte, die Antwort müsse ein einzelner Datensatz sein statt einer Liste, und ohne Zeile darin gibt es keine akzeptable Antwort. Lass den Header weg, und dieselbe Abfrage gibt eine leere Liste mit einem 200 zurück.","\u002Fblog\u002Fsupabase-single-row-error\u002Fcard-800x500.png",[493,494,495,496,497,498,499],"json object requested multiple (or no) rows returned","pgrst116","supabase single row error","supabase single() error","406 not acceptable supabase","maybesingle supabase","supabase returns no rows but row exists",{},true,"\"Multiple (or no) rows returned\" heißt meist: keine Zeilen","\u002Fblog\u002Fsupabase-single-row-error","2026-10-15",{"title":5,"description":472},"blog\u002Fsupabase-single-row-error",[508,509,510],"\"JSON object requested, multiple (or no) rows returned\" ist der Fehler PGRST116, und er heißt: deine Abfrage kam mit einer anderen Zahl von Zeilen zurück als genau einer. Fast immer ist diese Zahl null.","Mit eingeschalteter Row Level Security kommt eine Zeile, die dein Besucher nicht lesen darf, als gar keine Zeile zurück. Ein Datensatz, den du im Supabase Table Editor siehst, kann in deiner App fehlen, während mit den Daten alles in Ordnung ist.","Nimm maybeSingle(), wo nichts zu finden eine zulässige Antwort ist, und single(), wo es das nicht ist. Setz vorher eine Abfrage im SQL Editor ab, damit du weißt, welcher der beiden Fälle vorliegt.","SfJ9lrRH19mLSRtU6eIWZU_Pc_YeHS08ZEwdVJOy8zQ",[513,519,525,531,537,543,549,555,561,567,573,580,586,592,598,604,610,616,622,628,634,640,646,652,658,664,665,671,677,683,689,695,701,707,713,719,725,731,737,743,749,755,761,767,773,779,784,790,796,802,808,814,820,826,832,838,844,850,856,862,868,874,879,885,891,897,903,909,915,921,927,933,939,945,951,957,962,968,974,980,986,992,998,1004,1009,1015,1021,1027,1032,1038],{"path":514,"title":515,"description":516,"published":517,"category":469,"image":518,"draft":473},"\u002Fblog\u002Fmax-client-connections-reached","Supabase \"max client connections reached\" erklärt","Supabase \"max client connections reached\": Der Pooler hat keinen Platz für noch einen Client. Der Port in deinem Connection String setzt das Limit.","2026-11-09","\u002Fblog\u002Fmax-client-connections-reached\u002Fcard-800x500.png",{"path":520,"title":521,"description":522,"published":523,"category":469,"image":524,"draft":473},"\u002Fblog\u002Funsupported-provider-provider-is-not-enabled","Supabase-Fehler: \"Unsupported provider: provider is not enabled\"","\"Unsupported provider: provider is not enabled\" heißt: Google-Login ist in deinem Supabase-Projekt aus. Die Lösung, und was bei redirect_uri_mismatch hilft.","2026-11-08","\u002Fblog\u002Funsupported-provider-provider-is-not-enabled\u002Fcard-800x500.png",{"path":526,"title":527,"description":528,"published":529,"category":469,"image":530,"draft":473},"\u002Fblog\u002Fviolates-foreign-key-constraint","Supabase-Fehler \"violates foreign key constraint\" beim Einfügen","Supabase \"insert or update on table violates foreign key constraint\": Deine Zeile zeigt auf eine, die es nicht gibt. Welche, warum, und die Lösung.","2026-11-07","\u002Fblog\u002Fviolates-foreign-key-constraint\u002Fcard-800x500.png",{"path":532,"title":533,"description":534,"published":535,"category":469,"image":536,"draft":473},"\u002Fblog\u002Fnull-value-violates-not-null-constraint","Supabase-Fehler \"null value in column violates not-null constraint\"","Supabase \"null value in column violates not-null constraint\": Eine Pflichtspalte kam leer an. Woher die Null kommt, und die Lösung.","2026-11-06","\u002Fblog\u002Fnull-value-violates-not-null-constraint\u002Fcard-800x500.png",{"path":538,"title":539,"description":540,"published":541,"category":469,"image":542,"draft":473},"\u002Fblog\u002Fauth-session-missing","Supabase \"Auth session missing!\": wo die Sitzung geblieben ist","\"Auth session missing!\" heißt: supabase-js fand keine angemeldete Sitzung und fragte Supabase gar nicht erst. Wo die Sitzung blieb, und die Lösung je Fall.","2026-11-05","\u002Fblog\u002Fauth-session-missing\u002Fcard-800x500.png",{"path":544,"title":545,"description":546,"published":547,"category":469,"image":548,"draft":473},"\u002Fblog\u002Finvalid-claim-missing-sub-claim","Supabase \"invalid claim: missing sub claim\": niemand ist angemeldet","\"invalid claim: missing sub claim\" heißt: Supabase Auth bekam ein echtes Token ohne Nutzer darin, deinen Projektschlüssel statt einer Sitzung.","2026-11-04","\u002Fblog\u002Finvalid-claim-missing-sub-claim\u002Fcard-800x500.png",{"path":550,"title":551,"description":552,"published":553,"category":469,"image":554,"draft":473},"\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function","\"Failed to send a request to the Edge Function\": der echte Grund","\"Failed to send a request to the Edge Function\" heißt: Der Browser hat keine lesbare Antwort bekommen. Seine Konsole sagt, warum, und ob deine Funktion lief.","2026-11-03","\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function\u002Fcard-800x500.png",{"path":556,"title":557,"description":558,"published":559,"category":469,"image":560,"draft":473},"\u002Fblog\u002Fsupabase-auth-redirects-to-localhost","Warum Supabase-E-Mail-Links auf localhost:3000 weiterleiten","Leitet Supabase auf localhost:3000 um, ist die Site URL unverändert, oder deine Adresse fehlt in Redirect URLs. Die Lösung und der Platzhalter, den du meidest.","2026-11-02","\u002Fblog\u002Fsupabase-auth-redirects-to-localhost\u002Fcard-800x500.png",{"path":562,"title":563,"description":564,"published":565,"category":469,"image":566,"draft":473},"\u002Fblog\u002Femail-link-is-invalid-or-has-expired","Supabase \"Email link is invalid or has expired\" bei einem neuen Link","Bei einem Link von vor einer Minute heißt Supabases \"Email link is invalid or has expired\" meist: Ein Mailfilter hat ihn zuerst benutzt. Prüfen und beheben.","2026-11-01","\u002Fblog\u002Femail-link-is-invalid-or-has-expired\u002Fcard-800x500.png",{"path":568,"title":569,"description":570,"published":571,"category":469,"image":572,"draft":473},"\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout","Supabase \"canceling statement due to statement timeout\" erklärt","Supabase \"canceling statement due to statement timeout\": Eine Abfrage lief länger als ihre Rolle darf, 3 Sekunden für Besucher. Prüf zuerst die RLS-Regel.","2026-10-31","\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout\u002Fcard-800x500.png",{"path":574,"title":575,"description":576,"published":577,"category":578,"image":579,"draft":473},"\u002Fblog\u002Fdatabase-error-deleting-user","\"Database error deleting user\" in Supabase und was mitgelöscht wird","\"Database error deleting user\" in Supabase heißt: Deine Datenbank hat das Löschen abgelehnt. Der Grund steht im Log, die Lösung entscheidet, was mitgeht.","2026-10-30","Backups","\u002Fblog\u002Fdatabase-error-deleting-user\u002Fcard-800x500.png",{"path":581,"title":582,"description":583,"published":584,"category":469,"image":585,"draft":473},"\u002Fblog\u002Fstripe-webhook-no-signatures-found","\"No signatures found matching the expected signature\" bei Supabase","Ein Stripe-Webhook in einer Supabase Edge Function meldet \"No signatures found matching the expected signature\"? Zwei Ursachen. Prüfe weiter.","2026-10-29","\u002Fblog\u002Fstripe-webhook-no-signatures-found\u002Fcard-800x500.png",{"path":587,"title":588,"description":589,"published":590,"category":469,"image":591,"draft":473},"\u002Fblog\u002Fsupabase-invalid-login","\"Invalid login credentials\" in Supabase: die drei Ursachen","Supabase sagt \"Invalid login credentials\" bei falschem Passwort, unbekannter E-Mail und Google-Konto. So erkennst du, welcher Fall es ist.","2026-10-28","\u002Fblog\u002Fsupabase-invalid-login\u002Fcard-800x500.png",{"path":593,"title":594,"description":595,"published":596,"category":469,"image":597,"draft":473},"\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code","\"Edge Function returned a non-2xx status code\": der echte Fehler","\"Edge Function returned a non-2xx status code\" heißt: Deine Supabase-Funktion hat mit einem Fehler geantwortet. So liest du den echten.","2026-10-27","\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code\u002Fcard-800x500.png",{"path":599,"title":600,"description":601,"published":602,"category":469,"image":603,"draft":473},"\u002Fblog\u002Fcertificate-not-trusted","Zertifikat nicht vertrauenswürdig: drei Ursachen außer Ablauf","Zertifikat nicht vertrauenswürdig, obwohl das Datum stimmt? Es nennt eine andere Adresse, hat sich selbst signiert oder seiner Kette fehlt ein Glied.","2026-10-26","\u002Fblog\u002Fcertificate-not-trusted\u002Fcard-800x500.png",{"path":605,"title":606,"description":607,"published":608,"category":469,"image":609,"draft":473},"\u002Fblog\u002Finvalid-input-syntax-for-type-uuid","Supabase \"invalid input syntax for type uuid\": was im Zitat steht","Supabase \"invalid input syntax for type uuid\" heißt: Deine App hat etwas geschickt, das keine ID ist. Zitat lesen, Abfrage zurückhalten, Spalte behalten.","2026-10-25","\u002Fblog\u002Finvalid-input-syntax-for-type-uuid\u002Fcard-800x500.png",{"path":611,"title":612,"description":613,"published":614,"category":469,"image":615,"draft":473},"\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint","Supabase \"duplicate key value violates unique constraint\" erklärt","Supabase \"duplicate key value violates unique constraint\" heißt: Der Wert ist schon vergeben. Spalte finden, Lösung wählen, Wert vom Bildschirm fernhalten.","2026-10-24","\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint\u002Fcard-800x500.png",{"path":617,"title":618,"description":619,"published":620,"category":469,"image":621,"draft":473},"\u002Fblog\u002Fsupabase-relation-does-not-exist","Supabase \"relation does not exist\", obwohl die Tabelle da ist","Supabase \"relation does not exist\" oder PGRST205: Keine Tabelle passt zu Name und Schema deiner Abfrage. Vier Prüfungen, und was eine Freigabe öffnet.","2026-10-23","\u002Fblog\u002Fsupabase-relation-does-not-exist\u002Fcard-800x500.png",{"path":623,"title":624,"description":625,"published":626,"category":469,"image":627,"draft":473},"\u002Fblog\u002Fsupabase-function-not-found","Supabase PGRST202: \"Could not find the function in the schema cache\"","Supabase \"Could not find the function in the schema cache\" nennt die Argumente, die deine App geschickt hat. Vergleich sie mit der Funktion.","2026-10-22","\u002Fblog\u002Fsupabase-function-not-found\u002Fcard-800x500.png",{"path":629,"title":630,"description":631,"published":632,"category":469,"image":633,"draft":473},"\u002Fblog\u002Fsupabase-schema-cache-column-error","Supabase PGRST204: \"Could not find the column in the schema cache\"","Supabase \"Could not find the column in the schema cache\" heißt meist: Der Name passt nicht. Vier Prüfungen und der Einzeiler zum Neuladen.","2026-10-21","\u002Fblog\u002Fsupabase-schema-cache-column-error\u002Fcard-800x500.png",{"path":635,"title":636,"description":637,"published":638,"category":469,"image":639,"draft":473},"\u002Fblog\u002Fsupabase-email-rate-limit-exceeded","Supabase \"Email Rate Limit Exceeded\": zwei Limits, ein Fehlercode","Supabase \"Email Rate Limit Exceeded\" begrenzt jede E-Mail deines Projekts: 2 pro Stunde beim eingebauten Absender. Was zählt und wie du es anhebst.","2026-10-20","\u002Fblog\u002Fsupabase-email-rate-limit-exceeded\u002Fcard-800x500.png",{"path":641,"title":642,"description":643,"published":644,"category":469,"image":645,"draft":473},"\u002Fblog\u002Fsupabase-users-logged-out","Supabase \"Invalid Refresh Token: Refresh Token Not Found\": 3 Ursachen","Supabase \"Invalid Refresh Token: Refresh Token Not Found\" meldet deine Nutzer ab. Drei Ursachen, und wie das Auth-Log sie trennt.","2026-10-19","\u002Fblog\u002Fsupabase-users-logged-out\u002Fcard-800x500.png",{"path":647,"title":648,"description":649,"published":650,"category":469,"image":651,"draft":473},"\u002Fblog\u002Fpermission-denied-for-schema-public","Supabase \"permission denied for schema public\": drei Ursachen","Supabase \"permission denied for schema public\" heißt: Ein Grant auf das Schema fehlt. Was ihn entfernt hat und welche Zeile ihn zurückbringt.","2026-10-18","\u002Fblog\u002Fpermission-denied-for-schema-public\u002Fcard-800x500.png",{"path":653,"title":654,"description":655,"published":656,"category":469,"image":657,"draft":473},"\u002Fblog\u002Fsupabase-bucket-not-found","Supabase \"Bucket not found\": die drei Dinge, die es bedeutet","Supabase \"Bucket not found\" ist eins von drei Dingen: ein öffentlicher Link zu einem privaten Bucket, ein ungenauer Name oder das falsche Projekt.","2026-10-17","\u002Fblog\u002Fsupabase-bucket-not-found\u002Fcard-800x500.png",{"path":659,"title":660,"description":661,"published":662,"category":469,"image":663,"draft":473},"\u002Fblog\u002Fsupabase-invalid-jwt","Supabase invalid JWT: Welcher Schlüssel streikt hier?","Ein Supabase invalid JWT ist PGRST301: ein signiertes Token hat die Prüfung nicht bestanden. In neueren Projekten ist das die Sitzung, nicht der API-Schlüssel.","2026-10-16","\u002Fblog\u002Fsupabase-invalid-jwt\u002Fcard-800x500.png",{"path":503,"title":5,"description":472,"published":504,"category":469,"image":491,"draft":473},{"path":666,"title":667,"description":668,"published":669,"category":469,"image":670,"draft":473},"\u002Fblog\u002Fdatabase-error-saving-new-user","\"Database error saving new user\" in Supabase: wo du nachsiehst","\"Database error saving new user\" heißt: etwas an deiner Supabase-Registrierung ist fehlgeschlagen. Der echte Fehler steht in deinen Logs.","2026-10-14","\u002Fblog\u002Fdatabase-error-saving-new-user\u002Fcard-800x500.png",{"path":672,"title":673,"description":674,"published":675,"category":469,"image":676,"draft":473},"\u002Fblog\u002Fwhat-is-supabase","Was ist Supabase? Die Datenbank, die dein Builder ausgesucht hat","Was ist Supabase: die Datenbank, der Login und der Dateispeicher hinter deiner App. Supabase betreibt die Server, die Regeln zu deinen Zeilen gehören dir.","2026-10-13","\u002Fblog\u002Fwhat-is-supabase\u002Fcard-800x500.png",{"path":678,"title":679,"description":680,"published":681,"category":469,"image":682,"draft":473},"\u002Fblog\u002Faws-access-key-exposed-in-frontend","Ein offengelegter AWS-Schlüssel im Frontend ist kein OpenAI-Key","Ein im Frontend offengelegter AWS-Zugriffsschlüssel liest und schreibt deinen Speicher. Die Lösung ist meist eine presigned URL, kein neuer Schlüssel.","2026-10-12","\u002Fblog\u002Faws-access-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":684,"title":685,"description":686,"published":687,"category":469,"image":688,"draft":473},"\u002Fblog\u002Fstorage-upload-violates-row-level-security","\"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.","2026-10-11","\u002Fblog\u002Fstorage-upload-violates-row-level-security\u002Fcard-800x500.png",{"path":690,"title":691,"description":692,"published":693,"category":469,"image":694,"draft":473},"\u002Fblog\u002Fbase44-security-scan","Base44 Security Scan: das, was nur er sehen kann","Der Base44 Security Scan prüft sieben Arten von Problemen von innen. Hier ist die Hälfte, die er liest und sonst niemand, und die Hälfte, die er nie ansieht.","2026-10-10","\u002Fblog\u002Fbase44-security-scan\u002Fcard-800x500.png",{"path":696,"title":697,"description":698,"published":699,"category":469,"image":700,"draft":473},"\u002Fblog\u002Fapi-key-leaked-what-to-do","Dein API-Key wurde geleakt. Die richtige Reihenfolge","Ein API-Key wurde geleakt und du weißt nicht, was zuerst zu tun ist. Nicht jeder Key im Frontend ist ein Leck, und die Reihenfolge zählt mehr als das Tempo.","2026-10-09","\u002Fblog\u002Fapi-key-leaked-what-to-do\u002Fcard-800x500.png",{"path":702,"title":703,"description":704,"published":705,"category":469,"image":706,"draft":473},"\u002Fblog\u002Finfinite-recursion-in-policy-for-relation","\"Infinite recursion detected in policy\" ohne RLS abzuschalten","\"Infinite recursion detected in policy for relation\" heißt: Deine Policy hat die Tabelle gefragt, die sie schützt. So brichst du den Kreis.","2026-10-08","\u002Fblog\u002Finfinite-recursion-in-policy-for-relation\u002Fcard-800x500.png",{"path":708,"title":709,"description":710,"published":711,"category":469,"image":712,"draft":473},"\u002Fblog\u002Fno-api-key-found-in-request","\"No API key found in request\" in Supabase, und die falsche Lösung","\"No API key found in request\" heißt, deine Supabase-Anfrage kam ohne Schlüssel an. Die meisten Antworten zeigen stattdessen auf deine Datenbankregeln.","2026-10-07","\u002Fblog\u002Fno-api-key-found-in-request\u002Fcard-800x500.png",{"path":714,"title":715,"description":716,"published":717,"category":469,"image":718,"draft":473},"\u002Fblog\u002Fis-base44-safe","Ist Base44 sicher? Was 5.442 echte Base44-Apps zeigten","Ist Base44 sicher? Wir haben 5.442 laufende Base44-Apps mit neun Checks geprüft. Fast alle bekamen ein B, aus Gründen, die der Inhaber nie gewählt hat.","2026-10-06","\u002Fblog\u002Fis-base44-safe\u002Fcard-800x500.png",{"path":720,"title":721,"description":722,"published":723,"category":469,"image":724,"draft":473},"\u002Fblog\u002Fmove-a-secret-to-an-edge-function","API-Schlüssel verstecken: ab in eine Supabase Edge Function","Einen API-Schlüssel verstecken heißt, ihn aus dem Browser zu nehmen. Eine Supabase Edge Function ist der kleinste Ort dafür, und zwei Schritte zählen mehr.","2026-10-05","\u002Fblog\u002Fmove-a-secret-to-an-edge-function\u002Fcard-800x500.png",{"path":726,"title":727,"description":728,"published":729,"category":469,"image":730,"draft":473},"\u002Fblog\u002Fenv-file-exposed-on-your-server","Ist deine .env-Datei öffentlich? Zwölf Pfade zum Prüfen","Ist deine .env-Datei auf deinem eigenen Webserver öffentlich? Zwölf Adressen sagen es dir, und ein Treffer heißt: alles darin ist längst öffentlich.","2026-10-04","\u002Fblog\u002Fenv-file-exposed-on-your-server\u002Fcard-800x500.png",{"path":732,"title":733,"description":734,"published":735,"category":469,"image":736,"draft":473},"\u002Fblog\u002Fis-v0-safe","v0-Sicherheit: alle 1.790 gescannten v0-Apps bekamen ein A","v0-Sicherheit, gemessen an 1.790 laufenden v0-Apps: Jede bekam ein A. Nur 17 nannten eine Datenbank, und genau das misst das A vor allem.","2026-10-03","\u002Fblog\u002Fis-v0-safe\u002Fcard-800x500.png",{"path":738,"title":739,"description":740,"published":741,"category":469,"image":742,"draft":473},"\u002Fblog\u002Fis-bolt-safe","Ist Bolt sicher? Was 1.123 echte Bolt-Apps zeigten","Ist Bolt sicher? Wir haben 1.123 laufende Bolt-Apps mit neun Checks geprüft. Das Hosting war sauber. Die Funde waren Schlüssel und offene Tabellen in den Apps.","2026-10-02","\u002Fblog\u002Fis-bolt-safe\u002Fcard-800x500.png",{"path":744,"title":745,"description":746,"published":747,"category":469,"image":748,"draft":473},"\u002Fblog\u002Fis-supabase-down-or-your-app","Ist Supabase down oder liegt es an deiner App? So erkennst du es","Ist Supabase down oder liegt es an deiner App? Ein pausiertes Projekt, eine volle Datenbank und ein eigener Fehler sehen gleich aus. Vier Prüfungen helfen.","2026-10-01","\u002Fblog\u002Fis-supabase-down-or-your-app\u002Fcard-800x500.png",{"path":750,"title":751,"description":752,"published":753,"category":469,"image":754,"draft":473},"\u002Fblog\u002Fdoes-supabase-encrypt-my-data","Verschlüsselt Supabase meine Daten? Ja. Wovor das schützt","Verschlüsselt Supabase Daten? Ja: AES-256 im Ruhezustand, TLS bei der Übertragung, SOC 2 und ISO 27001. Was jedes abdeckt und welches Leck keines stoppt.","2026-09-30","\u002Fblog\u002Fdoes-supabase-encrypt-my-data\u002Fcard-800x500.png",{"path":756,"title":757,"description":758,"published":759,"category":469,"image":760,"draft":473},"\u002Fblog\u002Fsupabase-free-plan-limits","Supabase Gratis-Tarif: die Limits und was an jedem passiert","Die Limits des Supabase-Gratis-Tarifs: 500 MB Datenbank, 5 GB Egress und keine Backups. Was an jeder Grenze passiert und was $25 für Pro ändern.","2026-09-29","\u002Fblog\u002Fsupabase-free-plan-limits\u002Fcard-800x500.png",{"path":762,"title":763,"description":764,"published":765,"category":578,"image":766,"draft":473},"\u002Fblog\u002Ftest-your-supabase-backup","Teste dein Supabase-Backup, bevor du es brauchst","So testest du dein Supabase-Backup: in ein Übungsprojekt einspielen, Zeilen zählen, anmelden und die Zeile suchen, die einer abgeschnittenen Datei fehlt.","2026-09-28","\u002Fblog\u002Ftest-your-supabase-backup\u002Fcard-800x500.png",{"path":768,"title":769,"description":770,"published":771,"category":578,"image":772,"draft":473},"\u002Fblog\u002Fsupabase-backup-github-action","Kostenloses Supabase-Backup per GitHub Action, mit Haken","Eine Supabase-Backup-GitHub-Action kostet nichts und passt für viele Apps. Der Workflow, der richtige Connection String und das Egress pro Lauf.","2026-09-27","\u002Fblog\u002Fsupabase-backup-github-action\u002Fcard-800x500.png",{"path":774,"title":775,"description":776,"published":777,"category":578,"image":778,"draft":473},"\u002Fblog\u002Fdownload-your-supabase-backup","Warum du dein Supabase-Backup nicht herunterladen kannst","Dein Supabase-Backup kannst du auf aktuellen Projekten nicht herunterladen, weil die Tageskopie physisch ist. Wie du es prüfst und selbst eine Kopie hältst.","2026-09-26","\u002Fblog\u002Fdownload-your-supabase-backup\u002Fcard-800x500.png",{"path":780,"title":781,"description":782,"published":777,"category":469,"image":783,"draft":473},"\u002Fblog\u002Fsupabase-permission-denied-for-table","Supabase \"permission denied for table\": der fehlende Grant","Ab 30. Oktober antwortet eine neue Supabase-Tabelle mit \"permission denied for table\", bis du Zugriff erteilst. Der Grant aus der E-Mail ist die halbe Lösung.","\u002Fblog\u002Fsupabase-permission-denied-for-table\u002Fcard-800x500.png",{"path":785,"title":786,"description":787,"published":788,"category":469,"image":789,"draft":473},"\u002Fblog\u002Fopen-api-endpoint-exposed","Ist ein offener API-Endpunkt ein Sicherheitsproblem? Sieh ins JSON","Dein Scan hat einen offenen API-Endpunkt gemeldet. Ob das zählt, hängt davon ab, was zurückkam, und die meisten hier gehörten der Plattform.","2026-09-25","\u002Fblog\u002Fopen-api-endpoint-exposed\u002Fcard-800x500.png",{"path":791,"title":792,"description":793,"published":794,"category":469,"image":795,"draft":473},"\u002Fblog\u002Flovable-security-scan","Lovable Security Scan: das Eine, was er nicht beweist","Lovable Security Scan: was Quick Scan und Deep Scan prüfen, wann welcher läuft, und das Eine, was kein Scan von innen beweisen kann.","2026-09-24","\u002Fblog\u002Flovable-security-scan\u002Fcard-800x500.png",{"path":797,"title":798,"description":799,"published":800,"category":578,"image":801,"draft":473},"\u002Fblog\u002Fsupabase-backup-auth-users","Warum in deinem Supabase-Dump keine Nutzer stehen","Führe supabase db dump allein aus und du bekommst die Form deiner Datenbank und keine einzige Zeile, und das auth-Schema mit deinen Nutzern fehlt ganz.","2026-09-23","\u002Fblog\u002Fsupabase-backup-auth-users\u002Fcard-800x500.png",{"path":803,"title":804,"description":805,"published":806,"category":469,"image":807,"draft":473},"\u002Fblog\u002Fdomain-and-certificate-expiry","Domain abgelaufen, Website offline: was jetzt passiert","Deine Domain ist abgelaufen und deine Website ist offline. Welche Frist jetzt läuft, warum das Zertifikat das kleinere Problem ist, und wie du beides prüfst.","2026-09-22","\u002Fblog\u002Fdomain-and-certificate-expiry\u002Fcard-800x500.png",{"path":809,"title":810,"description":811,"published":812,"category":469,"image":813,"draft":473},"\u002Fblog\u002Fis-lovable-safe","Ist Lovable sicher? Was 18.554 echte Lovable-Apps zeigten","Ist Lovable sicher? Wir haben 18.554 laufende Lovable-Apps mit neun Checks geprüft. Die Plattform war die sauberste von fünf. Die Funde saßen in den Apps.","2026-09-21","\u002Fblog\u002Fis-lovable-safe\u002Fcard-800x500.png",{"path":815,"title":816,"description":817,"published":818,"category":469,"image":819,"draft":473},"\u002Fblog\u002Fvibe-coded-app-security-checklist","Die Sicherheits-Checkliste für Vibe-Coding, in neun Prüfungen","Eine Sicherheits-Checkliste für Vibe-Coding mit neun Punkten, die jeder von außen an deiner Live-App nachprüfen kann, jeder mit einem Test in einer Zeile.","2026-09-20","\u002Fblog\u002Fvibe-coded-app-security-checklist\u002Fcard-800x500.png",{"path":821,"title":822,"description":823,"published":824,"category":469,"image":825,"draft":473},"\u002Fblog\u002Fstripe-secret-key-in-frontend","Ein geheimer Stripe-Schlüssel im Frontend kann Geld bewegen","Ein geheimer Stripe-Schlüssel im Frontend kann erstatten, abbuchen und jeden Kundendatensatz lesen, den du hast. Dein pk_live_-Schlüssel gehört dorthin.","2026-09-19","\u002Fblog\u002Fstripe-secret-key-in-frontend\u002Fcard-800x500.png",{"path":827,"title":828,"description":829,"published":830,"category":469,"image":831,"draft":473},"\u002Fblog\u002Fvite-and-next-public-env-vars","Vite-Env-Variablen offengelegt: der Präfix heißt veröffentlichen","Vite-Env-Variablen offengelegt: Deine App hat getan, was der Präfix verlangt. VITE_ und NEXT_PUBLIC_ heißen veröffentlichen, und die KI kannte den Preis nie.","2026-09-18","\u002Fblog\u002Fvite-and-next-public-env-vars\u002Fcard-800x500.png",{"path":833,"title":834,"description":835,"published":836,"category":469,"image":837,"draft":473},"\u002Fblog\u002Fbase44-source-maps","Base44-Sicherheit: was ein Scan meldet und was du ändern kannst","Base44-Sicherheit auf 5.438 gescannten Apps: Drei Befunde auf fast jeder gehören der Plattform, die Source Map ist das Base44-Badge, und deine Liste ist kurz.","2026-09-17","\u002Fblog\u002Fbase44-source-maps\u002Fcard-800x500.png",{"path":839,"title":840,"description":841,"published":842,"category":469,"image":843,"draft":473},"\u002Fblog\u002Fis-cursor-ai-safe","Ist Cursor AI sicher? Editor, Code und die App, die du veröffentlichst","Ist Cursor AI sicher? Drei Fragen in einer Suche: was Cursor behält, was sein Code falsch macht und ob deine veröffentlichte App offen steht.","2026-09-16","\u002Fblog\u002Fis-cursor-ai-safe\u002Fcard-800x500.png",{"path":845,"title":846,"description":847,"published":848,"category":469,"image":849,"draft":473},"\u002Fblog\u002Fis-replit-safe","Ist Replit sicher? Was wir in 3.042 Replit-Apps gefunden haben","Ist Replit sicher? Wir haben 3.042 laufende Replit-Apps mit neun externen Checks geprüft. Die Funde saßen in der veröffentlichten App, nicht im Hosting.","2026-09-15","\u002Fblog\u002Fis-replit-safe\u002Fcard-800x500.png",{"path":851,"title":852,"description":853,"published":854,"category":578,"image":855,"draft":473},"\u002Fblog\u002Fsupabase-storage-backup","Supabase Storage Backup: deine Datenbankkopie hat keine Dateien","Ein Supabase Storage Backup ist eine eigene Aufgabe. Datenbank-Backups enthalten die Liste deiner Dateien und keine davon, also bleibt jeder Upload kaputt.","2026-09-14","\u002Fblog\u002Fsupabase-storage-backup\u002Fcard-800x500.png",{"path":857,"title":858,"description":859,"published":860,"category":578,"image":861,"draft":473},"\u002Fblog\u002Fsupabase-point-in-time-recovery","Supabase Point-in-Time Recovery: Kosten und Grenzen","Supabase Point-in-Time Recovery spult deine Datenbank auf jede Sekunde der letzten Woche zurück. $100 im Monat zusätzlich zu Pro, und nur die Datenbank.","2026-09-13","\u002Fblog\u002Fsupabase-point-in-time-recovery\u002Fcard-800x500.png",{"path":863,"title":864,"description":865,"published":866,"category":578,"image":867,"draft":473},"\u002Fblog\u002Fsupabase-project-paused-recover","Supabase-Projekt pausiert? Deine Daten sind noch da","Supabase hat dein Projekt nach einer Woche ohne Aktivität pausiert. Gelöscht ist nichts, Wiederherstellen steht neben dem Namen, und du hast ein Jahr.","2026-09-12","\u002Fblog\u002Fsupabase-project-paused-recover\u002Fcard-800x500.png",{"path":869,"title":870,"description":871,"published":872,"category":469,"image":873,"draft":473},"\u002Fblog\u002Fsafest-ai-app-builder","Welcher KI-App-Builder ist am sichersten? 30.998 Apps im Test","Welcher KI-App-Builder ist am sichersten? Wir haben 30.998 aktive Apps von Lovable, Base44, Replit, v0 und Bolt gescannt. Der Builder entscheidet das nicht.","2026-09-11","\u002Fblog\u002Fsafest-ai-app-builder\u002Fcard-800x500.png",{"path":447,"title":875,"description":876,"published":877,"category":469,"image":878,"draft":473},"Row Level Security für jede Supabase-Tabelle aktivieren und prüfen","Row Level Security in Supabase ohne Policy sperrt eine Tabelle komplett. Eine Policy ohne den Schalter bringt gar nichts. Hier ist das SQL, und der Test.","2026-09-10","\u002Fblog\u002Fenable-rls-on-every-supabase-table\u002Fcard-800x500.png",{"path":880,"title":881,"description":882,"published":883,"category":469,"image":884,"draft":473},"\u002Fblog\u002Fsupabase-rls-disabled-in-public","Supabase \"RLS disabled in public\": was die Warnung übersieht","Supabase meldet \"RLS disabled in public\" als Fehler. Zur Lese-Policy, die deine Tabelle genauso offen lässt, sagt der Advisor gar nichts.","2026-09-09","\u002Fblog\u002Fsupabase-rls-disabled-in-public\u002Fcard-800x500.png",{"path":886,"title":887,"description":888,"published":889,"category":469,"image":890,"draft":473},"\u002Fblog\u002Frotate-supabase-service-role-key","Geleakten Supabase-service_role-Schlüssel richtig tauschen","Supabase sagt: erst das Leck schließen. Andere Anleitungen: sofort tauschen. Was richtig ist, hängt davon ab, wohin dein service_role-Schlüssel gelangt ist.","2026-09-08","\u002Fblog\u002Frotate-supabase-service-role-key\u002Fcard-800x500.png",{"path":892,"title":893,"description":894,"published":895,"category":469,"image":896,"draft":473},"\u002Fblog\u002Fvibe-coding-security-scanners-compared","Vibe-Coding-Security-Scanner im Vergleich, unserer eingeschlossen","Der beste Vibe-Coding-Security-Scanner hängt an drei Fragen, die keine Funktionsliste beantwortet. Acht Tools im Vergleich, mit Preisen und unseren Lücken.","2026-09-07","\u002Fblog\u002Fvibe-coding-security-scanners-compared\u002Fcard-800x500.png",{"path":898,"title":899,"description":900,"published":901,"category":469,"image":902,"draft":473},"\u002Fblog\u002Fsupabase-security-checker","Supabase Security Checker: die fünf Prüfungen selbst machen","Ein Supabase Security Checker liest deine veröffentlichte App statt deiner Projekteinstellungen. Hier sind die fünf Prüfungen und wie du jede selbst ausführst.","2026-09-06","\u002Fblog\u002Fsupabase-security-checker\u002Fcard-800x500.png",{"path":904,"title":905,"description":906,"published":907,"category":469,"image":908,"draft":473},"\u002Fblog\u002Fvibe-coding-security-scanner","Vibe-Coding-Security-Scanner: was ein URL-Scan übersieht","Ein Vibe-Coding-Security-Scanner liest deine laufende App von außen. Was das abdeckt, die vier Dinge, die er nicht sehen kann, und wie du das Ergebnis liest.","2026-09-05","\u002Fblog\u002Fvibe-coding-security-scanner\u002Fcard-800x500.png",{"path":910,"title":911,"description":912,"published":913,"category":469,"image":914,"draft":473},"\u002Fblog\u002Fmissing-security-headers","Fehlende Sicherheitsheader: wann sie wirklich zählen","Fehlende Sicherheitsheader ist unser häufigster Befund. Wogegen sie schützen, und wann sie die unwichtigste Zeile in deinem Bericht sind.","2026-09-04","\u002Fblog\u002Fmissing-security-headers\u002Fcard-800x500.png",{"path":916,"title":917,"description":918,"published":919,"category":469,"image":920,"draft":473},"\u002Fblog\u002Fopenai-api-key-exposed-in-frontend","Dein OpenAI-API-Schlüssel liegt im Frontend. Tausch ihn aus.","Ein OpenAI-API-Schlüssel im Frontend lässt sich an keine Domain binden. Tausch ihn heute, leg den Aufruf hinter deinen Server und begrenze das Budget.","2026-09-03","\u002Fblog\u002Fopenai-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":922,"title":923,"description":924,"published":925,"category":469,"image":926,"draft":473},"\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps","API-Schlüssel im Frontend: was 30.998 Apps wirklich ausliefern","Ein API-Schlüssel im Frontend ist meistens ein Google-Maps-Schlüssel. Wir haben 30.998 aktive Vibe-Coding-Apps gescannt und gezählt, was wirklich austritt.","2026-09-02","\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps\u002Fcard-800x500.png",{"path":928,"title":929,"description":930,"published":931,"category":578,"image":932,"draft":473},"\u002Fblog\u002Fsupabase-backup-tools-compared","Supabase-Backup-Tools im Vergleich, unseres eingeschlossen","Vier Arten von Supabase-Backup-Tool, was jedes wirklich kopiert und wann eine kostenlose GitHub Action jeden Anbieter schlägt, uns eingeschlossen.","2026-09-01","\u002Fblog\u002Fsupabase-backup-tools-compared\u002Fcard-800x500.png",{"path":934,"title":935,"description":936,"published":937,"category":469,"image":938,"draft":473},"\u002Fblog\u002Freplit-secrets-explained","Secrets in Replit nutzen, und was trotzdem veröffentlicht wird","Secrets in Replit nutzen: anlegen, auslesen und die zwei Gründe beheben, warum undefined zurückkommt. Dazu die Schlüssel, die das Werkzeug nicht schützt.","2026-08-31","\u002Fblog\u002Freplit-secrets-explained\u002Fcard-800x500.png",{"path":940,"title":941,"description":942,"published":943,"category":578,"image":944,"draft":473},"\u002Fblog\u002Fback-up-supabase-free-tier","Supabase Gratis-Tarif: Backup ohne Terminal selbst machen","Im Supabase Gratis-Tarif gibt es keine Backups, die Kopie musst du selbst machen. Wie das im Dashboard geht und was der CSV-Weg auslässt.","2026-08-30","\u002Fblog\u002Fback-up-supabase-free-tier\u002Fcard-800x500.png",{"path":946,"title":947,"description":948,"published":949,"category":469,"image":950,"draft":473},"\u002Fblog\u002Fis-supabase-secure","Ist Supabase sicher? Ja. Dein Projekt ist eine eigene Frage","Ist Supabase sicher? Die Plattform ist auditiert, verschlüsselt und pentestet. Supabase schreibt selbst auf, wo das aufhört und deine Einstellungen anfangen.","2026-08-29","\u002Fblog\u002Fis-supabase-secure\u002Fcard-800x500.png",{"path":952,"title":953,"description":954,"published":955,"category":469,"image":956,"draft":473},"\u002Fblog\u002Fwhere-to-find-supabase-api-keys","Wo du deine Supabase API-Keys findest: anon, service_role, URL","Projekt-URL, anon-Schlüssel und service_role-Schlüssel liegen auf einer Seite im Dashboard. Wo sie ist, und welcher der vier Werte in deine App gehört.","2026-08-28","\u002Fblog\u002Fwhere-to-find-supabase-api-keys\u002Fcard-800x500.png",{"path":452,"title":958,"description":959,"published":960,"category":469,"image":961,"draft":473},"New row violates row-level security policy in Supabase: was jetzt?","\"New row violates row-level security policy\" heißt, Supabase hat einen Schreibvorgang abgelehnt. Die schnelle Lösung öffnet die Tabelle wieder für alle.","2026-08-27","\u002Fblog\u002Fnew-row-violates-row-level-security-policy\u002Fcard-800x500.png",{"path":963,"title":964,"description":965,"published":966,"category":469,"image":967,"draft":473},"\u002Fblog\u002Fcors-wildcard-security-risk","Ist eine CORS-Wildcard ein Sicherheitsrisiko? Meist nicht.","Ist eine CORS-Wildcard ein Sicherheitsrisiko? Meist ist sie die Voreinstellung deines Builders und gibt nichts preis, was dein Server nicht ohnehin herausgab.","2026-08-26","\u002Fblog\u002Fcors-wildcard-security-risk\u002Fcard-800x500.png",{"path":969,"title":970,"description":971,"published":972,"category":578,"image":973,"draft":473},"\u002Fblog\u002Fsupabase-branching-is-not-a-backup","Supabase Branching ist kein Backup. Es geht nur vorwärts.","Warum Supabase Branching kein Backup ist: Ein Branch startet ohne deine Daten, und ein Merge bringt nur das Schema. Wofür es gut ist und was stattdessen hilft.","2026-08-25","\u002Fblog\u002Fsupabase-branching-is-not-a-backup\u002Fcard-800x500.png",{"path":975,"title":976,"description":977,"published":978,"category":578,"image":979,"draft":473},"\u002Fblog\u002Fhow-to-restore-a-supabase-backup","Supabase-Backup wiederherstellen, und was danach kaputt ist","Wie du ein Supabase-Backup aus dem Dashboard oder aus einer Dump-Datei wiederherstellst, was ersetzt wird und warum die App danach kaputt sein kann.","2026-08-24","\u002Fblog\u002Fhow-to-restore-a-supabase-backup\u002Fcard-800x500.png",{"path":981,"title":982,"description":983,"published":984,"category":469,"image":985,"draft":473},"\u002Fblog\u002Fsupabase-storage-bucket-public","Dein Supabase-Storage-Bucket ist öffentlich. Ist das ein Problem?","Ein öffentlicher Supabase-Storage-Bucket heißt: Wer die URL einer Datei hat, kann sie öffnen. Er heißt nicht, dass jemand den Inhalt auflisten darf.","2026-08-23","\u002Fblog\u002Fsupabase-storage-bucket-public\u002Fcard-800x500.png",{"path":987,"title":988,"description":989,"published":990,"category":469,"image":991,"draft":473},"\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend","Ist ein Google-API-Schlüssel im Frontend ein Problem?","Ein Google-API-Schlüssel im Frontend ist der Fund unseres Scanners Nummer eins, und meistens unbedenklich. Eine kostenlose Einstellung entscheidet darüber.","2026-08-22","\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":993,"title":994,"description":995,"published":996,"category":578,"image":997,"draft":473},"\u002Fblog\u002Fai-agent-deleted-my-database","Ein KI-Agent hat meine Supabase-Daten gelöscht. Was hole ich zurück?","Ein KI-Agent hat Daten aus deiner Datenbank gelöscht. Was du zurückholst, stand schon vorher fest, und die nächsten Minuten entscheiden über den Rest.","2026-08-21","\u002Fblog\u002Fai-agent-deleted-my-database\u002Fcard-800x500.png",{"path":999,"title":1000,"description":1001,"published":1002,"category":469,"image":1003,"draft":473},"\u002Fblog\u002Fcan-anyone-read-your-supabase-database","Kann jeder deine Supabase-Datenbank lesen? 3.680 Apps im Test","Kann jeder deine Supabase-Datenbank ohne Login lesen? Wir haben 30.998 aktive Apps aus KI-Buildern gescannt und gemessen, wie oft die Antwort ja lautet.","2026-08-18","\u002Fblog\u002Fcan-anyone-read-your-supabase-database\u002Fcard-800x500.png",{"path":1005,"title":1006,"description":1007,"published":1002,"category":469,"image":1008,"draft":473},"\u002Fblog\u002Fsource-maps-exposed-in-production","Source-Maps öffentlich: deine App veröffentlicht ihren Quellcode","Eine öffentliche Source-Map lässt jeden den Originalcode deiner App lesen, Kommentare inklusive. Der 30-Sekunden-Check, und was wirklich zählt.","\u002Fblog\u002Fsource-maps-exposed-in-production\u002Fcard-800x500.png",{"path":1010,"title":1011,"description":1012,"published":1013,"category":469,"image":1014,"draft":473},"\u002Fblog\u002Fsupabase-new-api-keys","Supabase publishable key: ist er derselbe wie der anon key?","Supabase hat anon und service_role durch öffentliche und geheime Schlüssel ersetzt. Welcher gehört in deine App, und welcher nie?","2026-08-12","\u002Fblog\u002Fsupabase-new-api-keys\u002Fcard-800x500.png",{"path":1016,"title":1017,"description":1018,"published":1019,"category":578,"image":1020,"draft":473},"\u002Fblog\u002Fdoes-supabase-back-up-my-database","Sichert Supabase meine Datenbank? Das hängt von deinem Tarif ab.","Sichert Supabase deine Datenbank? Auf bezahlten Tarifen täglich, im Gratis-Tarif gar nicht. So findest du heraus, was du hast und was es nicht abdeckt.","2026-08-11","\u002Fblog\u002Fdoes-supabase-back-up-my-database\u002Fcard-800x500.png",{"path":1022,"title":1023,"description":1024,"published":1025,"category":469,"image":1026,"draft":473},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","Supabase Row Level Security ist an. Die Tabelle ist trotzdem offen.","Supabase Row Level Security anzuschalten schützt keine Tabelle. Erst deine Policies tun das, und die, die deine App repariert hat, lässt oft alle herein.","2026-08-10","\u002Fblog\u002Fsupabase-rls-on-but-table-still-public\u002Fcard-800x500.png",{"path":1028,"title":1029,"description":1030,"published":1025,"category":578,"image":1031,"draft":473},"\u002Fblog\u002Fversion-history-is-not-a-backup","Der Versionsverlauf ist kein Backup. Er holt keine Tabelle zurück.","Lovable und Bolt führen einen Versionsverlauf für deinen Code. Deine Datenbank ist ein eigener Dienst, und ein Rücksprung holt deine Daten nicht zurück.","\u002Fblog\u002Fversion-history-is-not-a-backup\u002Fcard-800x500.png",{"path":1033,"title":1034,"description":1035,"published":1036,"category":578,"image":1037,"draft":473},"\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database","Drei Wege, eine Supabase-Datenbank zu sichern, und was fehlt","Das Dashboard, pg_dump und ein verwalteter Dienst. Was jeder Weg wirklich sichert, was er stillschweigend auslässt und welcher den Kontoverlust übersteht.","2026-08-09","\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database\u002Fcard-800x500.png",{"path":1039,"title":1040,"description":1041,"published":1036,"category":469,"image":1042,"draft":473},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","Welche API-Schlüssel im Frontend sicher sind, und welche nicht","Dein Supabase-anon-Schlüssel darf öffentlich sein. Der service_role-Schlüssel nicht. Er ignoriert jede Regel, die du setzt. So erkennst du den Unterschied.","\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend\u002Fcard-800x500.png",1794213638782]