[{"data":1,"prerenderedAt":467},["ShallowReactive",2],{"blog-fr-new-row-violates-row-level-security-policy":3},{"id":4,"title":5,"body":6,"category":425,"cover":426,"coverAlt":427,"description":428,"draft":429,"extension":430,"faq":431,"image":447,"keywords":448,"meta":455,"navigation":456,"ogTitle":457,"path":458,"published":459,"seo":460,"stem":461,"tldr":462,"updated":459,"__hash__":466},"blog_fr\u002Fblog\u002Fnew-row-violates-row-level-security-policy.md","New row violates row-level security policy sur Supabase : et après ?",{"type":7,"value":8,"toc":414},"minimark",[9,13,24,32,37,40,47,50,63,66,70,73,76,79,83,86,96,99,182,188,195,223,231,235,238,241,247,254,262,266,269,275,285,298,302,305,310,313,322,337,351,359,363,401],[10,11,12],"p",{},"Quelque chose vous a dit d'activer Row Level Security. L'advisor dans votre\ntableau de bord Supabase, le résultat d'un scan, une checklist, quelqu'un sur\nun Discord. Vous l'avez activé. Maintenant votre app n'arrive plus à\nenregistrer quoi que ce soit. Chaque tentative revient en disant que a new row\nviolates row-level security policy :",[14,15,20],"pre",{"className":16,"code":18,"language":19},[17],"language-text","new row violates row-level security policy for table \"profiles\"\n","text",[21,22,18],"code",{"__ignoreMap":23},"",[10,25,26,27,31],{},"Voici la partie que guide après guide raconte de travers : ",[28,29,30],"strong",{},"la réponse qui fait\ndisparaître cette erreur en dix secondes défait exactement ce que vous venez\nd'activer."," C'est le premier résultat que vous trouverez, elle agit\nimmédiatement, et elle laisse la table exactement là où elle était avant qu'on\nvous dise de la corriger.",[33,34,36],"h2",{"id":35},"ce-que-signifie-new-row-violates-row-level-security-policy","Ce que signifie \"new row violates row-level security policy\"",[10,38,39],{},"On a demandé à votre base de données d'enregistrer une ligne, elle a consulté\nles règles de cette table, n'en a trouvé aucune qui laisse entrer cette ligne\nprécise, et elle a refusé.",[10,41,42,43,46],{},"C'est tout le message. Rien n'est corrompu et rien n'a été perdu : la ligne\nn'a jamais été enregistrée, et le reste de la table est exactement comme il y a\nune minute. La formulation vient de Postgres, le moteur de base de données sur\nlequel tourne Supabase, et c'est pourquoi elle sonne comme de la mécanique\nplutôt que comme quelque chose écrit par votre builder. Supabase la transmet\ntelle quelle, avec son numéro à côté, ",[21,44,45],{},"42501",".",[10,48,49],{},"Ce que le message ne vous dira pas, c'est quelle règle manquait. Une seule\nphrase couvre trois situations différentes, et vous dire dans laquelle vous êtes\ndécrirait vos règles à celui qui a déclenché l'erreur :",[51,52,53,57,60],"ul",{},[54,55,56],"li",{},"La table a Row Level Security activé et aucune règle écrite.",[54,58,59],{},"Elle a une règle, et cette règle ne parle que de lecture.",[54,61,62],{},"Elle a une règle d'écriture, et la ligne que vous avez envoyée ne la satisfait pas.",[10,64,65],{},"Les trois impriment cette même ligne. La deuxième est la plus courante sur une\napp tout juste lancée, où une règle a été ajoutée pour que les écrans\nrefonctionnent et où l'enregistrement n'a jamais été évoqué.",[33,67,69],{"id":68},"pourquoi-elle-est-apparue-au-moment-où-vous-avez-activé-row-level-security","Pourquoi elle est apparue au moment où vous avez activé Row Level Security",[10,71,72],{},"Parce que l'activer refuse tout jusqu'à ce qu'une règle dise le contraire, et\nvotre propre app fait partie de tout.",[10,74,75],{},"C'est la séquence que presque tout le monde traverse. Vous activez le réglage.\nLes écrans se vident, car sans règle écrite la base ne remet plus de lignes à\npersonne, votre app comprise. Vous ajoutez une règle pour que les listes\nreviennent, en général la première que suggère un résultat de recherche ou votre\nbuilder. Les écrans se remplissent. Et la première fois que quelqu'un appuie\nsur enregistrer, cette erreur apparaît, sur une table que vous pensiez déjà\nréglée.",[10,77,78],{},"Rien n'a mal tourné dans cette séquence. La règle que vous avez ajoutée parlait\nde lecture, et enregistrer est une autre question que personne n'avait encore\nposée.",[33,80,82],{"id":81},"une-règle-a-deux-moitiés-et-une-seule-parle-de-lecture","Une règle a deux moitiés, et une seule parle de lecture",[10,84,85],{},"Une policy est une condition, et l'endroit où la base applique cette condition\ndépend de ce que vous lui avez demandé.",[10,87,88,91,92,95],{},[21,89,90],{},"USING"," s'applique aux lignes déjà présentes dans la table. Elle décide\nlesquelles vous avez le droit de voir, de modifier ou de retirer. ",[21,93,94],{},"WITH CHECK","\ns'applique à la ligne que vous essayez de créer, avant qu'elle n'existe où que\nce soit. Elle décide si cette ligne a le droit de voir le jour.",[10,97,98],{},"Cette seconde moitié est celle qui surprend, parce que c'est une règle\nconcernant quelque chose qui n'est pas encore là.",[100,101,102,118],"table",{},[103,104,105],"thead",{},[106,107,108,112,115],"tr",{},[109,110,111],"th",{},"Votre app demande à",[109,113,114],{},"Vérifié contre les lignes déjà dans la table",[109,116,117],{},"Vérifié contre la ligne écrite",[119,120,121,138,152,168],"tbody",{},[106,122,123,131,135],{},[124,125,126,127,130],"td",{},"lire (",[21,128,129],{},"select",")",[124,132,133],{},[21,134,90],{},[124,136,137],{},"rien à vérifier",[106,139,140,146,148],{},[124,141,142,143,130],{},"enregistrer une nouvelle ligne (",[21,144,145],{},"insert",[124,147,137],{},[124,149,150],{},[21,151,94],{},[106,153,154,160,164],{},[124,155,156,157,130],{},"modifier une ligne (",[21,158,159],{},"update",[124,161,162],{},[21,163,90],{},[124,165,166],{},[21,167,94],{},[106,169,170,176,180],{},[124,171,172,173,130],{},"retirer une ligne (",[21,174,175],{},"delete",[124,177,178],{},[21,179,90],{},[124,181,137],{},[183,184],"diagram",{"alt":185,"caption":186,"src":187},"Une même règle dessinée deux fois. À gauche elle pointe vers une pile de lignes déjà dans une table et deux d'entre elles reviennent. À droite la même règle pointe vers une seule ligne dessinée en contour, qui attend hors de la table, et elle est refusée.","La même condition, dirigée vers deux choses différentes. En lecture on l'interroge sur des lignes qui existent ; en enregistrement, sur une ligne qui n'existe pas encore.","\u002Fblog\u002Fnew-row-violates-row-level-security-policy\u002Fusing-and-with-check-1600x780.png",[10,189,190,191,194],{},"Une policy écrite en ",[21,192,193],{},"FOR SELECT"," ne porte jamais que la première moitié, parce\nqu'il n'y a aucune ligne nouvelle à vérifier quand quelqu'un lit. Elle ne peut\ndonc jamais autoriser un enregistrement, aussi permissive qu'elle paraisse.\nC'est tout le décalage, et il explique pourquoi vos lectures se sont rétablies\net pas vos écritures.",[196,197,199],"callout",{"type":198},"warn",[10,200,201,207,208,210,211,213,214,216,217,219,220,222],{},[28,202,190,203,206],{},[21,204,205],{},"FOR ALL"," se comporte autrement, et sans le dire."," Si\nvous en écrivez une avec une condition ",[21,209,90],{}," et sans ",[21,212,94],{},", Postgres\napplique cette même condition ",[21,215,90],{}," aux nouvelles lignes également. Une règle\n",[21,218,205],{}," disant que les lignes appartiennent à leur propriétaire refuse donc un\nenregistrement où le propriétaire ne correspond pas, sans qu'aucun ",[21,221,94],{},"\nn'apparaisse dans ce que vous avez écrit. Utile quand c'était voulu. Déroutant\nquand vous lisez une règle collée par quelqu'un d'autre.",[10,224,225,226,46],{},"Si vous préférez le voir de l'extérieur, notre scan gratuit demande à votre base\nen direct ce qu'un inconnu peut déjà y lire, sans compte et en une vingtaine de\nsecondes : ",[227,228,230],"a",{"href":229},"\u002F#scan","scanner votre app",[33,232,234],{"id":233},"le-correctif-qui-fait-cesser-lerreur-et-ce-quil-coûte","Le correctif qui fait cesser l'erreur, et ce qu'il coûte",[10,236,237],{},"Le plus rapide pour la faire disparaître est une règle qui autorise n'importe\nquelle écriture de n'importe qui, et c'est pour cela qu'elle est la réponse en\ntête presque partout.",[10,239,240],{},"Elle arrive en général sous cette forme :",[14,242,245],{"className":243,"code":244,"language":19},[17],"CREATE POLICY \"Enable insert for all users\"\n  ON public.profiles\n  FOR INSERT\n  WITH CHECK (true);\n",[21,246,244],{"__ignoreMap":23},[10,248,249,250,253],{},"Toute ligne satisfait ",[21,251,252],{},"true",", donc tout enregistrement est autorisé, celui de\nvotre app comme celui de n'importe qui d'autre détenant la clé qui voyage\ndedans. Redésactiver Row Level Security fait la même chose, en plus complet.",[10,255,256,257,261],{},"Les deux fonctionnent. Les deux vous laissent là où vous étiez avant que\nl'advisor ne signale la table, et ensuite aucune des deux ne montre le moindre\nsigne que quelque chose est ouvert, parce que votre app se comporte à\nl'identique dans les quatre combinaisons de réglage et de règle. Une table peut\nêtre activée, porter une policy valide, afficher un badge vert dans votre\ntableau de bord et remettre quand même ses lignes à un inconnu. C'est\n",[227,258,260],{"href":259},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","l'autre moitié de ce problème",",\net elle mérite d'être lue avant de coller quoi que ce soit.",[33,263,265],{"id":264},"la-règle-qui-laisse-votre-app-enregistrer-et-elle-seule","La règle qui laisse votre app enregistrer, et elle seule",[10,267,268],{},"Nommez à qui appartient la ligne, et comparez-le à celui qui demande :",[14,270,273],{"className":271,"code":272,"language":19},[17],"CREATE POLICY \"Users insert their own rows\"\n  ON public.profiles\n  FOR INSERT\n  TO authenticated\n  WITH CHECK (auth.uid() = user_id);\n",[21,274,272],{"__ignoreMap":23},[10,276,277,280,281,284],{},[21,278,279],{},"auth.uid()"," est celui qui est connecté et fait la requête. ",[21,282,283],{},"user_id"," est la\ncolonne de la ligne qui dit à qui elle appartient. Quand les deux correspondent,\nla ligne est enregistrée. Quand ce n'est pas le cas, ou quand personne n'est\nconnecté, elle est refusée, et la personne refusée voit le même message que\ncelui que vous regardez depuis tout à l'heure.",[10,286,287,288,291,292,294,295,297],{},"Deux détails de cette règle méritent leur place. ",[21,289,290],{},"TO authenticated"," veut dire\nque la règle s'applique aux visiteurs connectés ; retirez-le et la policy\ns'applique à tout le monde, inconnus compris. Et votre app doit réellement\nenvoyer la colonne ",[21,293,283],{},", car une règle qui compare ",[21,296,279],{}," à une\nvaleur arrivée vide ne peut jamais correspondre.",[33,299,301],{"id":300},"quand-la-règle-est-bonne-et-que-lerreur-revient-quand-même","Quand la règle est bonne et que l'erreur revient quand même",[10,303,304],{},"Regardez qui était connecté avant de relire la policy.",[183,306],{"alt":307,"caption":308,"src":309},"Trois tables côte à côte. Dans chacune une ligne dessinée en contour arrive par le haut et sa flèche s'arrête juste avant la règle en dessous. La règle de la première table est un contour pointillé vide, celle de la deuxième porte select, celle de la troisième insert. Une bande traverse les trois par le bas en portant le code 42501.","Trois causes différentes qui vous parviennent comme une seule phrase. Le code 42501 est le même dans les trois cas, et c'est pourquoi le message seul ne peut pas vous dire dans lequel vous êtes.","\u002Fblog\u002Fnew-row-violates-row-level-security-policy\u002Fthree-causes-one-message-1600x700.png",[10,311,312],{},"Trois explications couvrent l'essentiel de ce qui reste :",[10,314,315,318,319,321],{},[28,316,317],{},"Personne n'est connecté."," ",[21,320,279],{}," revient vide pour un visiteur qui ne\ns'est pas connecté, donc une règle qui le compare à une colonne de propriétaire\nne peut pas correspondre. C'est normal sur un formulaire d'inscription, une\nliste d'attente ou un formulaire de contact, et ceux-là ont besoin de leur\npropre règle décrivant ce qu'un inconnu a le droit d'ajouter.",[10,323,324,327,328,330,331,333,334,336],{},[28,325,326],{},"La colonne de propriétaire n'arrive jamais."," Votre règle compare\n",[21,329,279],{}," à ",[21,332,283],{},", et votre app envoie tout sauf ",[21,335,283],{},". La\ncomparaison se fait contre du vide et échoue à chaque fois.",[10,338,339,342,343,346,347,350],{},[28,340,341],{},"L'écriture part vers Storage."," Les fichiers téléversés atterrissent dans\nSupabase Storage, qui tient ses propres policies sur ",[21,344,345],{},"storage.objects"," plutôt\nque sur votre table. Une règle écrite sur ",[21,348,349],{},"profiles"," ne dit rien d'un fichier.",[10,352,353,354,358],{},"Il y a une quatrième explication, et c'est celle qu'il vaut mieux écarter tôt :\nsi l'enregistrement marche depuis l'aperçu de votre builder et échoue depuis\nvotre site en ligne, les deux n'utilisent pas la même clé. Une clé secrète\nignore toutes les règles que vous avez écrites, c'est sa raison d'être, donc\nune app qui n'enregistre que tant qu'une clé secrète est en jeu est une app\ndont les règles n'ont jamais vraiment été testées.\n",[227,355,357],{"href":356},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","Quelles clés d'API sont sûres dans votre frontend","\nexplique comment distinguer l'une de l'autre.",[33,360,362],{"id":361},"quoi-faire-aujourdhui","Quoi faire aujourd'hui",[364,365,366],"key-takeaways",{},[51,367,368,371,377,391,394],{},[54,369,370],{},"Lisez l'erreur comme un refus et non comme une panne. L'écriture n'a pas eu lieu, la table est inchangée, et il n'y a rien à récupérer.",[54,372,373,374,376],{},"Vérifiez si la table possède la moindre policy sur l'écriture. Une règle écrite en ",[21,375,193],{}," a réparé vos écrans et n'a rien dit de l'enregistrement.",[54,378,379,380,383,384,386,387,390],{},"Ajoutez une policy ",[21,381,382],{},"FOR INSERT"," dont la condition ",[21,385,94],{}," nomme le propriétaire de la ligne, et ajoutez la clause ",[21,388,389],{},"TO"," que vous vouliez.",[54,392,393],{},"Confirmez que votre app envoie réellement la colonne de propriétaire, puis réessayez d'enregistrer en étant connecté.",[54,395,396,397,400],{},"Gardez ",[21,398,399],{},"WITH CHECK (true)"," pour les tables dont le contenu vous irait sur une page publique. Pour tout ce qui contient une personne, accordez-lui les deux minutes.",[10,402,403,404,408,409,413],{},"Commencez par la table d'où venait l'erreur, et vérifiez toutes les autres\ntables sur lesquelles vous avez activé le réglage le même après-midi. La\n",[227,405,407],{"href":406},"\u002Fchecklist","checklist de sécurité en 10 minutes"," couvre ce qui reste ouvert\nd'ordinaire sur une app tout juste lancée, et le\n",[227,410,412],{"href":411},"\u002Fis-your-supabase-app-safe","guide de sécurité Supabase"," passe en revue le reste\nde ce qu'un inconnu peut atteindre.",{"title":23,"searchDepth":415,"depth":415,"links":416},3,[417,419,420,421,422,423,424],{"id":35,"depth":418,"text":36},2,{"id":68,"depth":418,"text":69},{"id":81,"depth":418,"text":82},{"id":233,"depth":418,"text":234},{"id":264,"depth":418,"text":265},{"id":300,"depth":418,"text":301},{"id":361,"depth":418,"text":362},"Bases de la sécurité","\u002Fblog\u002Fnew-row-violates-row-level-security-policy\u002Fcover-1200x630.png","Une pile de lignes dans une table, avec une ligne de plus qui attend dehors, dessinée en contour parce qu'on ne l'a pas laissée entrer.","\"New row violates row-level security policy\" signifie que Supabase a refusé une écriture. Le correctif rapide rouvre la table à tout le monde.",false,"md",[432,435,438,441,444],{"q":433,"a":434},"Que signifie \"new row violates row-level security policy\" ?","Cela signifie qu'on a demandé à votre base de données d'enregistrer une ligne, qu'elle a consulté les règles de cette table et n'en a trouvé aucune qui laisse entrer cette ligne. Elle a donc refusé l'écriture. Rien n'a été perdu et rien n'est cassé, car la ligne n'a jamais été enregistrée et le reste de la table est intact. Le message vient de Postgres, le moteur de base de données sur lequel tourne Supabase, et il porte le code 42501. Ce qu'il ne vous dit délibérément pas, c'est quelle règle manquait, car le dire décrirait vos règles à celui qui a déclenché l'erreur.",{"q":436,"a":437},"J'ai ajouté une policy et la lecture marche. Pourquoi l'enregistrement échoue-t-il encore ?","Parce qu'une policy de lecture ne dit rien de l'écriture. Une règle porte une moitié USING, que la base applique aux lignes déjà présentes dans la table, et une moitié WITH CHECK, qu'elle applique à la ligne que vous essayez de créer. Une policy écrite en FOR SELECT n'a jamais que la première, puisqu'il n'y a aucune ligne nouvelle à vérifier quand on lit. Vos écrans se remplissent à nouveau et le premier enregistrement échoue toujours. Ajoutez une seconde policy FOR INSERT avec une condition WITH CHECK.",{"q":439,"a":440},"Est-ce que je peux simplement désactiver Row Level Security pour que ça disparaisse ?","Cela fait bien cesser l'erreur, et cela laisse chaque ligne de cette table lisible par quiconque possède la clé qui voyage dans votre app. Votre app fonctionne dans les deux cas, donc plus rien ensuite ne vous dit laquelle des deux vous avez choisie. Si la table contient des personnes, des commandes ou des messages, les deux minutes que coûte une vraie règle font la différence entre une table privée et une table publique.",{"q":442,"a":443},"Ma policy a l'air correcte et les inserts échouent quand même. Qu'est-ce que ça peut être ?","Trois choses expliquent la plupart des cas. Personne n'est connecté, donc auth.uid() revient vide et une règle qui le compare à une colonne de propriétaire ne peut jamais correspondre, ce qui est normal sur un formulaire d'inscription ou de contact. Ou bien votre app n'envoie pas du tout la colonne de propriétaire, et la règle compare contre une valeur arrivée vide. Ou bien l'écriture part vers Supabase Storage plutôt que vers une table, et Storage tient ses propres policies sur storage.objects.",{"q":445,"a":446},"Cette erreur veut-elle dire que quelqu'un a essayé d'attaquer mon app ?","Presque jamais. Sur une app tout juste lancée, c'est presque toujours votre propre app qui se fait refuser, parce que Row Level Security a été activé avant qu'une règle couvrant vos propres écritures existe. Cela vaut quand même la peine de la lire plutôt que de l'écarter : le même message apparaît quand une requête qui ne devrait pas écrire dans cette table est refusée, et le message seul ne vous permet pas de distinguer les deux.","\u002Fblog\u002Fnew-row-violates-row-level-security-policy\u002Fcard-800x500.png",[449,450,451,452,453,454],"new row violates row-level security policy","supabase rls insert policy","rls bloque insert","supabase with check policy","activer row level security supabase","erreur row level security",{},true,"New row violates row-level security policy","\u002Fblog\u002Fnew-row-violates-row-level-security-policy","2026-08-27",{"title":5,"description":428},"blog\u002Fnew-row-violates-row-level-security-policy",[463,464,465],"New row violates row-level security policy signifie que votre base de données a consulté les règles de cette table et n'en a trouvé aucune qui autorise la ligne que vous enregistriez. Elle a refusé l'écriture et laissé la table telle quelle.","Un seul message couvre trois situations différentes : aucune règle, une règle qui ne parle que de lecture, ou une règle d'écriture que votre ligne ne satisfait pas.","La réponse en tête de toutes les recherches fait cesser l'erreur en autorisant n'importe quelle écriture de n'importe qui. La règle que vous voulez vraiment coûte environ deux minutes de plus.","hJW4Yck7QDM-G-JGsIq_XGRA6Ad2CMH2wqxMRrDcj6o",1787826048205]