[{"data":1,"prerenderedAt":467},["ShallowReactive",2],{"blog-pt-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_pt\u002Fblog\u002Fnew-row-violates-row-level-security-policy.md","New row violates row-level security policy no Supabase. E agora?",{"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",{},"Alguma coisa mandou você ligar o Row Level Security. O advisor dentro do seu\npainel do Supabase, o resultado de um scan, um checklist, alguém num Discord.\nVocê ligou. Agora o seu app não consegue salvar absolutamente nada. Toda\ntentativa volta dizendo que a new row violates 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],{},"Aqui está a parte que guia após guia conta errado: ",[28,29,30],"strong",{},"a resposta que faz esse\nerro sumir em dez segundos desfaz exatamente o que você acabou de ligar."," É o\nprimeiro resultado que você vai achar, funciona na hora, e deixa a tabela\nexatamente onde ela estava antes de alguém mandar você consertar.",[33,34,36],"h2",{"id":35},"o-que-significa-new-row-violates-row-level-security-policy","O que significa \"new row violates row-level security policy\"",[10,38,39],{},"Pediram ao seu banco para salvar uma linha, ele conferiu as regras daquela\ntabela, não achou nenhuma que deixasse aquela linha específica entrar, e\nrecusou.",[10,41,42,43,46],{},"Essa é a mensagem inteira. Nada está corrompido e nada se perdeu: a linha nunca\nchegou a ser salva, e o resto da tabela está igualzinho a um minuto atrás. A\nredação vem do Postgres, o motor de banco de dados em que o Supabase roda, e por\nisso ela soa a maquinário em vez de soar a algo escrito pelo seu builder. O\nSupabase repassa do jeito que veio, com o número do lado, ",[21,44,45],{},"42501",".",[10,48,49],{},"O que a mensagem não vai te dizer é qual regra estava faltando. Uma frase só\ncobre três situações diferentes, e te dizer em qual você está descreveria as\nsuas regras para quem provocou o erro:",[51,52,53,57,60],"ul",{},[54,55,56],"li",{},"A tabela está com o Row Level Security ligado e nenhuma regra escrita.",[54,58,59],{},"Ela tem uma regra, e essa regra fala apenas de leitura.",[54,61,62],{},"Ela tem uma regra de escrita, e a linha que você mandou não satisfaz ela.",[10,64,65],{},"As três imprimem essa mesma linha. A segunda é a comum num app recém-lançado,\nonde uma regra foi adicionada para as telas voltarem a funcionar e de salvar\nninguém falou.",[33,67,69],{"id":68},"por-que-ele-apareceu-bem-na-hora-em-que-você-ligou-o-row-level-security","Por que ele apareceu bem na hora em que você ligou o Row Level Security",[10,71,72],{},"Porque ligar recusa tudo até uma regra dizer o contrário, e o seu próprio app\nfaz parte de tudo.",[10,74,75],{},"Essa é a sequência que quase todo mundo passa. Você liga a configuração. As\ntelas ficam em branco, porque sem regra escrita o banco agora não entrega linha\npara ninguém, o seu app incluído. Você adiciona uma regra para as listas\nvoltarem, normalmente a primeira que um resultado de busca ou o seu builder\nsugere. As telas enchem. E na primeira vez que alguém aperta salvar, esse erro\naparece, numa tabela que você dava por resolvida.",[10,77,78],{},"Nada deu errado nessa sequência. A regra que você adicionou falava de leitura, e\nsalvar é outra pergunta que até ali ninguém tinha feito.",[33,80,82],{"id":81},"uma-regra-tem-duas-metades-e-só-uma-fala-de-leitura","Uma regra tem duas metades, e só uma fala de leitura",[10,84,85],{},"Uma policy é uma condição, e onde o banco aplica essa condição depende do que\nvocê pediu.",[10,87,88,91,92,95],{},[21,89,90],{},"USING"," se aplica às linhas que já estão na tabela. Ela decide quais você pode\nver, mudar ou tirar. ",[21,93,94],{},"WITH CHECK"," se aplica à linha que você está tentando\ncriar, antes de ela existir em qualquer lugar. Ela decide se aquela linha pode\nvir a existir.",[10,97,98],{},"Essa segunda metade é a parte que surpreende, porque é uma regra sobre algo que\nainda não está lá.",[100,101,102,118],"table",{},[103,104,105],"thead",{},[106,107,108,112,115],"tr",{},[109,110,111],"th",{},"O seu app pede para",[109,113,114],{},"Conferido contra as linhas que já estão na tabela",[109,116,117],{},"Conferido contra a linha sendo escrita",[119,120,121,138,152,168],"tbody",{},[106,122,123,131,135],{},[124,125,126,127,130],"td",{},"ler (",[21,128,129],{},"select",")",[124,132,133],{},[21,134,90],{},[124,136,137],{},"nada a conferir",[106,139,140,146,148],{},[124,141,142,143,130],{},"salvar uma linha nova (",[21,144,145],{},"insert",[124,147,137],{},[124,149,150],{},[21,151,94],{},[106,153,154,160,164],{},[124,155,156,157,130],{},"mudar uma linha (",[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],{},"tirar uma linha (",[21,174,175],{},"delete",[124,177,178],{},[21,179,90],{},[124,181,137],{},[183,184],"diagram",{"alt":185,"caption":186,"src":187},"Uma mesma regra desenhada duas vezes. À esquerda ela aponta para uma pilha de linhas que já estão dentro de uma tabela e duas delas voltam. À direita a mesma regra aponta para uma única linha desenhada em contorno, esperando fora da tabela, e ela é recusada.","A mesma condição, apontada para duas coisas diferentes. Na leitura ela é perguntada sobre linhas que existem; no salvamento, sobre uma linha que ainda não existe.","\u002Fblog\u002Fnew-row-violates-row-level-security-policy\u002Fusing-and-with-check-1600x780.png",[10,189,190,191,194],{},"Uma policy escrita com ",[21,192,193],{},"FOR SELECT"," só carrega a primeira metade, porque quando\nalguém lê não existe linha nova para conferir. Então ela nunca consegue permitir\num salvamento, por mais permissiva que pareça. É esse o descompasso inteiro, e\nele explica por que as suas leituras se recuperaram e as suas escritas não.",[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 comporta diferente, e caladinha."," Se você\nescrever uma com condição ",[21,209,90],{}," e sem ",[21,212,94],{},", o Postgres aplica essa\nmesma condição ",[21,215,90],{}," às linhas novas também. Então uma regra ",[21,218,205],{}," dizendo\nque as linhas pertencem ao dono delas recusa um salvamento em que o dono não\nbate, sem que nenhum ",[21,221,94],{}," apareça no que você escreveu. Útil quando era\nessa a intenção. Confuso quando você está lendo uma regra que outra pessoa\ncolou.",[10,224,225,226,46],{},"Se você preferir ver isso de fora, o nosso scan gratuito pergunta ao seu banco\nao vivo o que um estranho já consegue ler dele, sem conta e em uns 20 segundos:\n",[227,228,230],"a",{"href":229},"\u002F#scan","escanear o seu app",[33,232,234],{"id":233},"o-conserto-que-faz-o-erro-parar-e-o-que-ele-custa","O conserto que faz o erro parar, e o que ele custa",[10,236,237],{},"O jeito mais rápido de fazer isso sumir é uma regra que permita qualquer escrita\nde qualquer um, e é por isso que ela é a resposta do topo em quase todo lugar\nque você olhar.",[10,239,240],{},"Ela costuma chegar com esta cara:",[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],{},"Toda linha satisfaz ",[21,251,252],{},"true",", então todo salvamento é permitido, o do seu app e o\nde qualquer outra pessoa com a chave que viaja dentro dele. Desligar o Row Level\nSecurity de novo faz o mesmo serviço de forma ainda mais completa.",[10,255,256,257,261],{},"Os dois funcionam. Os dois deixam você onde estava antes de o advisor apontar a\ntabela, e depois nenhum dos dois mostra qualquer sinal de que algo está aberto,\nporque o seu app se comporta igualzinho nas quatro combinações de configuração e\nregra. Uma tabela pode estar ligada, ter uma policy válida, mostrar um selo\nverde no seu painel e ainda assim entregar as linhas dela para um estranho. Essa\né ",[227,258,260],{"href":259},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","a outra metade deste problema",",\ne vale ler antes de colar qualquer coisa.",[33,263,265],{"id":264},"a-regra-que-deixa-o-seu-app-salvar-e-só-o-seu-app","A regra que deixa o seu app salvar, e só o seu app",[10,267,268],{},"Nomeie a quem a linha pertence, e compare com quem está pedindo:",[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()"," é quem está logado e fazendo a requisição. ",[21,282,283],{},"user_id"," é a coluna na\nlinha que diz a quem ela pertence. Quando os dois batem, a linha é salva. Quando\nnão batem, ou quando não tem ninguém logado, ela é recusada, e quem foi recusado\nvê a mesma mensagem que você está olhando.",[10,286,287,288,291,292,294,295,297],{},"Dois detalhes dessa regra ganham o lugar deles. ",[21,289,290],{},"TO authenticated"," quer dizer\nque a regra vale para visitantes logados; tire isso e a policy passa a valer\npara todo mundo, estranhos incluídos. E o seu app precisa mandar de fato a\ncoluna ",[21,293,283],{},", porque uma regra que compara ",[21,296,279],{}," com um valor que\nchegou vazio nunca vai bater.",[33,299,301],{"id":300},"quando-a-regra-está-certa-e-o-erro-aparece-mesmo-assim","Quando a regra está certa e o erro aparece mesmo assim",[10,303,304],{},"Olhe quem estava logado antes de olhar a policy de novo.",[183,306],{"alt":307,"caption":308,"src":309},"Três tabelas lado a lado. Em cada uma, uma linha desenhada em contorno chega de cima e a seta dela para pouco antes da regra que está embaixo. A regra da primeira tabela é um contorno tracejado vazio, a da segunda traz select, a da terceira traz insert. Uma faixa corre embaixo das três levando o código 42501.","Três causas diferentes chegando até você como uma frase só. O código 42501 é o mesmo nas três, e é por isso que a mensagem sozinha não consegue te dizer em qual você está.","\u002Fblog\u002Fnew-row-violates-row-level-security-policy\u002Fthree-causes-one-message-1600x700.png",[10,311,312],{},"Três explicações cobrem quase tudo o que sobra:",[10,314,315,318,319,321],{},[28,316,317],{},"Não tem ninguém logado."," ",[21,320,279],{}," volta vazio para um visitante que não\nentrou, então uma regra que compara isso com uma coluna de dono não tem como\nbater. Isso é normal num formulário de cadastro, numa lista de espera ou num\nformulário de contato, e esses precisam de uma regra própria descrevendo o que\num estranho pode adicionar.",[10,323,324,327,328,330,331,333,334,336],{},[28,325,326],{},"A coluna de dono nunca chega."," A sua regra compara ",[21,329,279],{}," com\n",[21,332,283],{},", e o seu app manda tudo menos ",[21,335,283],{},". A comparação roda contra um\nvazio e falha toda vez.",[10,338,339,342,343,346,347,350],{},[28,340,341],{},"A escrita está indo para o Storage."," Uploads de arquivo caem no Supabase\nStorage, que mantém as próprias policies em ",[21,344,345],{},"storage.objects"," em vez de na sua\ntabela. Uma regra escrita em ",[21,348,349],{},"profiles"," não diz nada sobre um arquivo.",[10,352,353,354,358],{},"Tem uma quarta explicação, e é a que vale descartar cedo: se salvar funciona no\npreview do seu builder e falha no seu site no ar, os dois não estão usando a\nmesma chave. Uma chave secreta ignora toda regra que você escreveu, é para isso\nque ela serve, então um app que só salva enquanto tem uma chave secreta em jogo\né um app cujas regras nunca foram testadas de verdade.\n",[227,355,357],{"href":356},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","Quais chaves de API são seguras no seu frontend","\nmostra como distinguir uma da outra.",[33,360,362],{"id":361},"o-que-fazer-hoje","O que fazer hoje",[364,365,366],"key-takeaways",{},[51,367,368,371,377,391,394],{},[54,369,370],{},"Leia o erro como uma recusa e não como um defeito. A escrita não aconteceu, a tabela está intacta, e não tem nada para recuperar.",[54,372,373,374,376],{},"Confira se a tabela tem alguma policy sobre escrita. Uma regra escrita com ",[21,375,193],{}," consertou as suas telas e não disse nada sobre salvar.",[54,378,379,380,383,384,386,387,390],{},"Adicione uma policy ",[21,381,382],{},"FOR INSERT"," cuja condição ",[21,385,94],{}," nomeie o dono da linha, e adicione a cláusula ",[21,388,389],{},"TO"," que você quis dizer.",[54,392,393],{},"Confirme que o seu app manda mesmo a coluna de dono, e tente salvar de novo estando logado.",[54,395,396,397,400],{},"Deixe ",[21,398,399],{},"WITH CHECK (true)"," para tabelas cujo conteúdo você publicaria numa página pública. Para qualquer coisa com uma pessoa dentro, gaste os dois minutos.",[10,402,403,404,408,409,413],{},"Comece pela tabela de onde veio o erro, e confira toda outra tabela em que você\nligou a configuração na mesma tarde. O\n",[227,405,407],{"href":406},"\u002Fchecklist","checklist de segurança de 10 minutos"," cobre o que mais costuma\nficar aberto num app recém-lançado, e o\n",[227,410,412],{"href":411},"\u002Fis-your-supabase-app-safe","guia de segurança do Supabase"," passa pelo resto do\nque um estranho consegue alcançar.",{"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},"Noções de segurança","\u002Fblog\u002Fnew-row-violates-row-level-security-policy\u002Fcover-1200x630.png","Uma pilha de linhas dentro de uma tabela, com mais uma linha esperando fora, desenhada só em contorno porque não deixaram ela entrar.","\"New row violates row-level security policy\" significa que o Supabase recusou uma escrita. O conserto rápido reabre a tabela para qualquer um.",false,"md",[432,435,438,441,444],{"q":433,"a":434},"O que significa \"new row violates row-level security policy\"?","Significa que pediram ao seu banco para salvar uma linha, ele conferiu as regras daquela tabela e não achou nenhuma que deixasse aquela linha entrar. Então recusou a escrita. Nada foi perdido e nada está quebrado, porque a linha nunca chegou a ser salva e o resto da tabela está intacto. A mensagem vem do Postgres, o motor de banco de dados em que o Supabase roda, e ela carrega o código 42501. O que ela deliberadamente não diz é qual regra estava faltando, porque dizer isso descreveria as suas regras para quem provocou o erro.",{"q":436,"a":437},"Adicionei uma policy e a leitura funciona. Por que salvar continua falhando?","Porque uma policy sobre leitura não diz nada sobre escrita. Uma regra carrega uma metade USING, que o banco aplica às linhas que já estão na tabela, e uma metade WITH CHECK, que ele aplica à linha que você está tentando criar. Uma policy escrita com FOR SELECT só tem a primeira, já que na leitura não existe linha nova para conferir. As suas telas voltam a encher e o primeiro salvamento continua falhando. Adicione uma segunda policy FOR INSERT com uma condição WITH CHECK.",{"q":439,"a":440},"Posso simplesmente desligar o Row Level Security para isso sumir?","Isso faz o erro sumir, e deixa cada linha daquela tabela legível por qualquer um que tenha a chave que viaja dentro do seu app. O seu app funciona dos dois jeitos, então depois nada te diz qual dos dois você escolheu. Se a tabela guarda pessoas, pedidos ou mensagens, os dois minutos que custa escrever uma regra de verdade são a diferença entre uma tabela privada e uma pública.",{"q":442,"a":443},"Minha policy parece certa e os inserts continuam falhando. O que mais pode ser?","Três coisas explicam a maioria dos casos. Não tem ninguém logado, então auth.uid() volta vazio e uma regra que compara isso com uma coluna de dono nunca vai bater, o que é normal num formulário de cadastro ou de contato. Ou o seu app não manda a coluna de dono, e a regra compara contra um valor que chegou em branco. Ou a escrita vai para o Supabase Storage em vez de para uma tabela, e o Storage mantém as próprias policies em storage.objects.",{"q":445,"a":446},"Esse erro quer dizer que alguém tentou atacar o meu app?","Quase nunca. Num app recém-lançado é quase sempre o seu próprio app sendo recusado, porque o Row Level Security foi ligado antes de existir uma regra que cobrisse as suas próprias escritas. Ainda assim vale ler em vez de descartar: a mesma mensagem aparece quando uma requisição que não deveria estar escrevendo naquela tabela é recusada, e só pela mensagem você não distingue as duas.","\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 bloqueando insert","supabase with check policy","ativar row level security supabase","erro 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 significa que o seu banco conferiu as regras daquela tabela e não achou nenhuma que permitisse a linha que você estava salvando. Ele recusou a escrita e deixou a tabela como estava.","Uma mensagem só cobre três situações diferentes: nenhuma regra, uma regra que fala apenas de leitura, ou uma regra de escrita que a sua linha não satisfaz.","A resposta que lidera qualquer busca faz o erro parar permitindo qualquer escrita de qualquer um. A regra que você realmente quer custa uns dois minutos a mais.","oDUiqv2lmnQ3o8jdOSlJoHrwHySsabaB9QIioVo9xeg",1787826050863]