[{"data":1,"prerenderedAt":1042},["ShallowReactive",2],{"blog-es-supabase-single-row-error":3,"blog-index-es":511},{"id":4,"title":5,"body":6,"category":468,"cover":469,"coverAlt":470,"description":471,"draft":472,"extension":473,"faq":474,"image":490,"keywords":491,"meta":499,"navigation":500,"ogTitle":501,"path":502,"published":503,"seo":504,"stem":505,"tldr":506,"updated":503,"__hash__":510},"blog_es\u002Fblog\u002Fsupabase-single-row-error.md","Supabase \"multiple (or no) rows returned\" casi siempre es ninguna",{"type":7,"value":8,"toc":454},"minimark",[9,13,16,27,43,48,51,54,61,65,72,96,102,111,137,141,147,164,174,177,181,184,193,196,202,205,212,216,219,250,253,261,265,270,273,279,285,289,292,295,298,302,310,315,331,336,344,348,354,363,378,388,405,409,441],[10,11,12],"p",{},"Tu app le dice a alguien que un registro no se encuentra. Abres el Table Editor\nde Supabase y el registro está ahí, en la tabla, con el id correcto.",[10,14,15],{},"Esto es lo que volvió de la base:",[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],{},"Y esta es la parte que guía tras guía se salta: ",[31,32,33],"strong",{},"cero filas es una respuesta que\ntus propias reglas pueden producir, y se lee igual que unos datos que ya no\nestán."," Busca este mensaje y te dirán que cambies ",[24,36,37],{},".single()"," por\n",[24,40,41],{},".maybeSingle()",". Eso sí detiene el error. No te dice nada sobre si la fila\nfaltaba o si tu visitante nunca tuvo permiso para verla, y esos dos casos se\nreparan distinto.",[44,45,47],"h2",{"id":46},"qué-significa-json-object-requested-multiple-or-no-rows-returned","¿Qué significa \"JSON object requested, multiple (or no) rows returned\"?",[10,49,50],{},"Tu consulta le pidió a la base exactamente una fila y el resultado tenía otro\nnúmero. Casi siempre ese número es cero.",[10,52,53],{},"Piensa en una sala de lectura donde rellenas una papeleta y alguien detrás del\nmostrador va a buscar el libro. Tu papeleta dice: tráeme el único libro con este\nnúmero. El mostrador vuelve y te dice que no hay nada que coincida con la\npapeleta. Esa es la única respuesta que da el mostrador, y es la misma tanto si\nel libro nunca estuvo en el catálogo como si está en una estantería para la que\nno tienes permiso. Nadie está jugando contigo. El sistema de papeletas se\nconstruyó para que aquello para lo que no tienes permiso sencillamente no\naparezca en tu vista del catálogo.",[10,55,56,57,60],{},"Tu app es la que sostiene la papeleta, y el número con el que volvió el mostrador\nestá escrito en la línea ",[24,58,59],{},"details"," de la respuesta.",[44,62,64],{"id":63},"dos-mensajes-distintos-y-el-mismo-código-de-error","Dos mensajes distintos, y el mismo código de error",[10,66,67,68,71],{},"El código es estable y la frase no, así que guíate por ",[24,69,70],{},"PGRST116",".",[10,73,74,75,78,79,81,82,85,86,89,90,92,93,71],{},"Hay dos redacciones en circulación para este único error, y cuál ves depende de\nqué versión de PostgREST corre tu proyecto. PostgREST es el servidor que convierte\ntus tablas de Supabase en la API HTTP con la que habla tu app. Su documentación\nde la versión 12 da el mensaje\n",[24,76,77],{},"JSON object requested, multiple (or no) rows returned",", con una línea ",[24,80,59],{},"\nque dice\n",[24,83,84],{},"Results contain 0 rows, application\u002Fvnd.pgrst.object+json requires 1 row",". En\nlas versiones 13 y 14 la misma situación está documentada como\n",[24,87,88],{},"Cannot coerce the result to a single JSON object",", con ",[24,91,59],{}," diciendo\n",[24,94,95],{},"The result contains 0 rows",[10,97,98,99,101],{},"La frase antigua tiene una segunda vida más allá de los proyectos viejos. Cuando\nllamas a ",[24,100,41],{}," y coincide más de una fila, el cliente JavaScript de\nSupabase escribe el error él mismo en lugar de pasar uno del servidor, y el\nmensaje que escribe es la redacción antigua. Así que la primera frase sigue\nllegando a apps cuya base habría enviado la segunda.",[10,103,104,105,107,108,110],{},"Lo que no se mueve es el código. La tabla de errores de PostgREST lista\n",[24,106,70],{}," en 406 en las tres versiones, con la misma descripción: más de una\nfila, o ninguna, cuando se pedía exactamente una. Lee el campo ",[24,109,24],{}," e ignora la\nprosa.",[112,113,115],"callout",{"type":114},"warn",[10,116,117,120,121,124,125,128,129,132,133,136],{},[31,118,119],{},"Si comparas el mensaje como una cadena en tu propio código, compara el código\nen su lugar."," Un bloque ",[24,122,123],{},"catch"," que mide ",[24,126,127],{},"error.message"," contra\n",[24,130,131],{},"'JSON object requested, multiple (or no) rows returned'"," funciona hoy y deja de\nfuncionar el día que tu proyecto pase a un PostgREST más nuevo, sin ningún\ndespliegue tuyo en medio. ",[24,134,135],{},"error.code === 'PGRST116'"," sobrevive a eso.",[44,138,140],{"id":139},"por-qué-single-produce-esto","Por qué .single() produce esto",[10,142,143,144,146],{},"Porque ",[24,145,37],{}," es una instrucción sobre la forma de la respuesta y no un\nfiltro sobre los datos.",[10,148,149,150,152,153,156,157,160,161,71],{},"Cuando escribes ",[24,151,37],{},", el cliente de Supabase añade una cabecera a la\npetición: ",[24,154,155],{},"Accept: application\u002Fvnd.pgrst.object+json",". Esa cabecera le pide a la\nbase que envíe la fila sola, como un registro. Es lo que permite que tu código\nescriba ",[24,158,159],{},"data.name"," donde si no tendría que escribir ",[24,162,163],{},"data[0].name",[10,165,166,167,169,170,173],{},"La base lo cumple a rajatabla. Una fila vuelve como un registro. Cualquier otro\nnúmero de filas no se puede enviar en esa forma, así que la respuesta es un 406 y\nun objeto de error. Quita el ",[24,168,37],{}," y la consulta idéntica devuelve ",[24,171,172],{},"[]"," con\nun 200 y ningún error en ninguna parte.",[10,175,176],{},"Así que no hizo falta que nada se rompiera para producir esto. Un resultado vacío\nse convirtió en un error porque tu consulta dijo que la respuesta tenía que\ncontener exactamente un registro.",[44,178,180],{"id":179},"causa-1-la-fila-está-y-tus-reglas-dicen-que-no","Causa 1: la fila está y tus reglas dicen que no",[10,182,183],{},"Row Level Security no rechaza tu consulta. Le saca filas, y una fila sacada nunca\nestuvo en el resultado que se cuenta.",[10,185,186,187,189,190,192],{},"Row Level Security es el conjunto de reglas sobre cada tabla de Supabase que\ndecide, fila por fila, qué filas puede leer un visitante dado. Cuando ninguna\nregla permite a tu visitante leer la fila que tu consulta nombró, esa fila se\nquita antes de medir el resultado. El conteo es cero. Tu ",[24,188,37],{}," quería una.\nObtienes ",[24,191,70],{},", y ninguna parte de la respuesta menciona que hubo una regla\nde por medio.",[10,194,195],{},"Esa es otra vez la sala de lectura, y por eso el mostrador dice lo mismo dos\nveces. Tu permiso se aplica antes de que siquiera se busque en la estantería, así\nque un libro que no puedes llevarte y un libro que no existe producen una\npapeleta idéntica de vuelta.",[197,198],"diagram",{"alt":199,"caption":200,"src":201},"Una petición entra por la izquierda y se divide en dos carriles. En el carril de arriba una estantería tiene una fila dibujada en teal, y el carril queda detenido por una barra ámbar antes de llegar a la estantería. En el carril de abajo la estantería está vacía y dibujada con línea discontinua. Los dos carriles acaban en la misma bandeja vacía, marcada con un cero.","Una fila que tus reglas ocultan y una fila que no está dejan el resultado vacío igual. La respuesta cuenta filas, así que las dos llegan como el mismo error.","\u002Fblog\u002Fsupabase-single-row-error\u002Ftwo-reasons-one-answer-1600x700.png",[10,203,204],{},"Por eso también el Table Editor te despista. El SQL Editor y el Table Editor de\ntu consola de Supabase corren con privilegios a los que tus policies no se\naplican, así que te enseñan todas las filas. La petición de tu app lleva tu\npublishable key y la sesión de tu visitante, y a ella sí se le aplican las\npolicies. Dos vistas de una misma tabla, y solo una es la que reciben tus\nusuarios.",[10,206,207,208,211],{},"Esa diferencia se lee desde fuera, y así es como podemos contarla. Nuestro\nescáner lee apps en vivo como lo haría un desconocido. Detrás de 8.435 de las\napps que ha calificado hay un proyecto Supabase. En 3.680 de ellas la pregunta\n\"¿puede alguien sin cuenta leer esta tabla?\" obtuvo una respuesta utilizable, y\n",[31,209,210],{},"1.584 respondieron que no",": un desconocido que pidió las filas no recibió\nnada. Esa nada es la misma nada que recibe tu propia app cuando ninguna policy le\nencaja.",[44,213,215],{"id":214},"cómo-distinguir-una-fila-oculta-de-una-que-falta","Cómo distinguir una fila oculta de una que falta",[10,217,218],{},"Lanza la misma búsqueda dos veces, una donde las policies se aplican y otra donde\nno. Una consulta lo zanja.",[220,221,222,238,244],"ol",{},[223,224,225,226,229,230,233,234,237],"li",{},"Abre tu consola de Supabase, ve al ",[31,227,228],{},"SQL Editor"," y saca la fila por el mismo\nvalor que usó tu app:\n",[24,231,232],{},"select * from your_table where id = 'the-id-your-app-sent';",". Una consulta\ndesde el SQL Editor corre a través del rol ",[24,235,236],{},"postgres",", al que tus policies no\nse aplican.",[223,239,240,243],{},[31,241,242],{},"Si devuelve la fila",", la fila existe y algo entre tu app y la fila la quitó.\nEse algo es una policy, y estás en la causa 1. Lee las policies de esa tabla.",[223,245,246,249],{},[31,247,248],{},"Si tampoco devuelve nada",", la fila falta de verdad y estás en la causa 3 de\nmás abajo. Tus reglas no tienen nada que ver.",[10,251,252],{},"Haz esto antes de cambiar una línea de código. Las dos causas producen el mismo\nobjeto de error, y las dos reparaciones no se parecen en nada.",[10,254,255,256,71],{},"Ya que estás mirando las policies de esa tabla, vale la pena saber qué le dicen\nhoy a alguien sin ninguna cuenta. Nuestro escaneo gratuito lee tu app en vivo y\nte dice cuáles de tus tablas le responden a un desconocido. Tarda unos 20\nsegundos y no necesita cuenta: ",[257,258,260],"a",{"href":259},"\u002Fsecurity-scanner","escanear tu app",[44,262,264],{"id":263},"causa-2-volvieron-varias-filas","Causa 2: volvieron varias filas",[10,266,267,269],{},[24,268,37],{}," se usó sobre una búsqueda que puede coincidir con más de una fila.",[10,271,272],{},"Una búsqueda por clave primaria coincide con una fila o con ninguna, por\ndefinición. Una búsqueda por email, por slug, por nombre, por estado, por clave\nforánea: cualquiera de ellas puede tocar dos. La historia habitual es que la\ncolumna tenía un valor por fila en tus datos de prueba y dejó de tenerlo cuando\nllegó gente de verdad.",[10,274,275,276,278],{},"La respuesta te dice en qué causa estás. Las dos redacciones de la línea\n",[24,277,59],{}," dicen cuántas filas tenía el resultado. Cero te manda a la causa 1 o a\nla causa 3. Un número por encima de cero señala esta, y es el conteo de filas que\ncoincidieron.",[10,280,281,282,284],{},"La reparación no es ",[24,283,41],{},". Ese acepta cero filas y sigue dando error\ncon dos, así que aquí no cambia nada. O acotas la consulta a una fila con la\ncolumna que de verdad es única, o aceptas que hay varias y lees una lista.",[44,286,288],{"id":287},"causa-3-la-fila-ya-no-está","Causa 3: la fila ya no está",[10,290,291],{},"A veces la fila falta, y la consulta de la sección anterior es lo que lo\nconfirma.",[10,293,294],{},"Las razones corrientes, en el orden en que aparecen en una app vibe-codeada. El\nvalor por el que filtraba tu consulta estaba vacío, porque el id no había cargado\ncuando la consulta salió, así que no coincidió nada. La fila se borró, por ti o\npor un prompt que reescribió más de lo que esperabas. O la consulta nombra una\ntabla que se reconstruyó con otro nombre y las filas viejas se fueron con la\ntabla vieja.",[10,296,297],{},"Nada de eso es un problema de seguridad, y ninguno se arregla cambiando una\npolicy. Si el SQL Editor no encuentra nada, deja de leer sobre Row Level Security\ny ve a mirar qué está pasando tu app.",[44,299,301],{"id":300},"single-o-maybesingle-cuál-quiere-tu-consulta","single o maybeSingle: cuál quiere tu consulta",[10,303,304,306,307,309],{},[24,305,41],{}," donde no encontrar nada es una respuesta legítima. ",[24,308,37],{},"\ndonde no lo es.",[10,311,312,314],{},[24,313,37],{}," trata cualquier número de filas distinto de uno como un error. Es el\ncomportamiento correcto para una búsqueda por clave primaria, donde cero filas\nsignifica que el registro del que trata tu código no existe y seguir sería peor\nque parar.",[10,316,317,319,320,323,324,327,328,330],{},[24,318,41],{}," acepta cero filas: te entrega ",[24,321,322],{},"data"," como ",[24,325,326],{},"null",", sin error y\ncon un 200. Más de una fila sigue siendo un error, con el mismo código\n",[24,329,70],{},". Así que encaja con una fila de perfil que puede no haberse creado\ntodavía, o con un registro opcional para el que tu página pinta un estado vacío.",[197,332],{"alt":333,"caption":334,"src":335},"Dos carriles rotulados single y maybeSingle. Cada carril tiene tres casillas marcadas 0, 1 y 2. En el carril single la casilla 1 está aceptada en teal y las casillas 0 y 2 llevan una cruz ámbar. En el carril maybeSingle las casillas 0 y 1 están aceptadas y solo la casilla 2 está cruzada.","La única diferencia está en qué hace cada uno con un resultado vacío. Los dos rechazan dos filas, y ninguno cambia lo que la base devolvió de verdad.","\u002Fblog\u002Fsupabase-single-row-error\u002Fwhat-each-one-accepts-1600x640.png",[10,337,338,339,38,341,343],{},"Una cosa con la que hay que tener cuidado. Cambiar ",[24,340,37],{},[24,342,41],{}," cambia cómo se comporta tu app y no cambia nada de lo que envió\nla base. Si una policy escondía la fila, has convertido un error visible en una\npágina que se pinta como si el registro no existiera, para la única persona que\ntenía que verlo. El error te estaba diciendo algo. Haz el cambio después de la\nprueba de arriba, cuando sepas que cero es la respuesta honesta.",[44,345,347],{"id":346},"vigilar-tus-reglas-después-de-cambiarlas","Vigilar tus reglas después de cambiarlas",[10,349,350,353],{},[31,351,352],{},"Una policy que abres para quitarte este error es un cambio que nadie ve desde\ndentro de tu app."," Tu propia sesión sigue funcionando, el error ya no está, y si\nesa tabla ahora le responde a un desconocido es una pregunta que alguien tiene\nque ir a hacer.",[10,355,356],{},[31,357,358,362],{},[257,359,361],{"href":360},"\u002Fwebsite-monitoring","Reeve Monitor"," la hace por ti:",[364,365,366,369,372,375],"ul",{},[223,367,368],{},"las nueve comprobaciones cada hora, en hasta tres apps",[223,370,371],{},"un email el día que un nuevo escaneo califica tu app peor que el anterior",[223,373,374],{},"si la app responde, cada 60 segundos",[223,376,377],{},"un informe mensual de lo que vio",[10,379,380],{},[31,381,382,383,387],{},"Una regla aflojada lo bastante como para quitar un error puede dejar que un\ndesconocido cambie filas además de leerlas.\n",[257,384,386],{"href":385},"\u002Fsupabase-backups","Reeve Care"," guarda una copia de tu base de datos de Supabase\ndonde ningún cambio en tus reglas puede alcanzarla.",[364,389,390,393,396,399,402],{},[223,391,392],{},"una copia cifrada cada día, guardada fuera de tu cuenta de Supabase",[223,394,395],{},"cada copia verificada antes de contar, contando las filas de cada tabla",[223,397,398],{},"una restauración en un clic que guarda lo que hay ahora antes de reemplazarlo",[223,400,401],{},"tus archivos subidos también, en cuanto conectes un acceso de Storage",[223,403,404],{},"todo lo que hace Monitor",[44,406,408],{"id":407},"qué-hacer-hoy","Qué hacer hoy",[410,411,412],"key-takeaways",{},[364,413,414,423,429,432,438],{},[223,415,416,417,419,420,422],{},"Guíate por el campo ",[24,418,24],{},". ",[24,421,70],{}," llega bajo dos frases distintas, y cuál te toca depende de la versión de PostgREST que corre tu proyecto.",[223,424,425,426,428],{},"Lee el conteo de filas en la línea ",[24,427,59],{},". Cero significa resultado vacío. Por encima de cero, tu búsqueda tocó varias filas y necesita una columna única.",[223,430,431],{},"Con un resultado vacío, lanza la misma búsqueda en el SQL Editor antes de cambiar código. Si la fila vuelve ahí y no en tu app, una policy la quitó.",[223,433,434,435,437],{},"Pásate a ",[24,436,41],{}," cuando sepas que cero es la respuesta honesta. Sobre una fila que una policy esconde, reemplaza un error por una página vacía y sin aviso.",[223,439,440],{},"Después de cambiar una policy para quitarte esto, comprueba qué devuelve ahora esa tabla a alguien sin cuenta.",[10,442,443,444,448,449,453],{},"Empieza por una consulta en el SQL Editor, porque es la que decide qué mitad de\neste artículo te toca. Si resulta que una policy era la respuesta,\n",[257,445,447],{"href":446},"\u002Fblog\u002Fenable-rls-on-every-supabase-table","activar Row Level Security en cada tabla","\nenseña a escribir una regla que deje pasar a la persona correcta, y\n",[257,450,452],{"href":451},"\u002Fblog\u002Fnew-row-violates-row-level-security-policy","\"new row violates row-level security policy\"","\nes el mensaje que recibes cuando una policy rechaza una escritura que ves con tus\npropios ojos.",{"title":26,"searchDepth":455,"depth":455,"links":456},3,[457,459,460,461,462,463,464,465,466,467],{"id":46,"depth":458,"text":47},2,{"id":63,"depth":458,"text":64},{"id":139,"depth":458,"text":140},{"id":179,"depth":458,"text":180},{"id":214,"depth":458,"text":215},{"id":263,"depth":458,"text":264},{"id":287,"depth":458,"text":288},{"id":300,"depth":458,"text":301},{"id":346,"depth":458,"text":347},{"id":407,"depth":458,"text":408},"Fundamentos de seguridad","\u002Fblog\u002Fsupabase-single-row-error\u002Fcover-1200x630.png","Una papeleta de solicitud y una bandeja de devolución vacía sobre un mostrador, y detrás una estantería con una fila destacada en teal tras una barra ámbar.","Supabase devuelve PGRST116, \"JSON object requested, multiple (or no) rows returned\", cuando tu consulta no encontró nada. Una fila oculta parece ausente.",false,"md",[475,478,481,484,487],{"q":476,"a":477},"¿Qué significa PGRST116?","Significa que tu consulta le pidió a la base exactamente una fila y el resultado tenía otro número. PostgREST, la parte de Supabase que responde a tu app por HTTP, lo devuelve como HTTP 406 con el código PGRST116. El número está en la línea details de la respuesta, y casi siempre es cero.",{"q":479,"a":480},"¿Por qué mi consulta no devuelve filas si veo la fila en Supabase?","Porque el SQL Editor de tu consola corre con privilegios a los que tus policies de Row Level Security no se aplican, y tu app no. Si ninguna policy permite a tu visitante leer esa fila, la fila se quita de su resultado antes de contarlo, y lo que vuelve es un cero. La fila está ahí. Nunca estuvo en la respuesta.",{"q":482,"a":483},"¿Cuál es la diferencia entre single y maybeSingle?","single() trata cualquier número de filas distinto de uno como un error. maybeSingle() acepta cero filas y te entrega data como null, sin error, y sigue dando error cuando coincide más de una fila. Así que maybeSingle() encaja donde no encontrar nada es una respuesta legítima, como un perfil que todavía no existe, y single() encaja en una búsqueda por una columna que solo puede coincidir con una fila.",{"q":485,"a":486},"¿Row Level Security causa este error?","Es la causa más común en una app construida con Lovable, Bolt, Replit o v0. Row Level Security filtra filas fuera del resultado en lugar de rechazar la petición, así que una fila que nadie puede leer no se distingue de una fila que no existe. Las dos dan un conteo de cero, y una consulta que exige exactamente una fila falla con ambas.",{"q":488,"a":489},"¿Por qué es un 406?","406 Not Acceptable es el estado de una petición que el servidor no puede responder en la forma pedida. Tu consulta llevaba una cabecera Accept que decía que la respuesta debía ser un registro único y no una lista, y sin ninguna fila que poner dentro no hay respuesta aceptable que enviar. Quita esa cabecera y la misma consulta devuelve una lista vacía con un 200.","\u002Fblog\u002Fsupabase-single-row-error\u002Fcard-800x500.png",[492,493,494,495,496,497,498],"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\" casi siempre es ninguna fila","\u002Fblog\u002Fsupabase-single-row-error","2026-10-15",{"title":5,"description":471},"blog\u002Fsupabase-single-row-error",[507,508,509],"\"JSON object requested, multiple (or no) rows returned\" es el error PGRST116, y significa que tu consulta volvió con un número de filas distinto de uno. Casi siempre ese número es cero.","Con Row Level Security encendida, una fila que tu visitante no puede leer vuelve como ninguna fila. Así que un registro que ves en el Table Editor de Supabase puede faltar en tu app mientras los datos están perfectamente bien.","Usa maybeSingle() donde no encontrar nada sea una respuesta legítima y single() donde no lo sea. Lanza antes una consulta en el SQL Editor, para saber cuál de los dos casos tienes.","FhbUm9Y0lj7HzzTLAVjM10CzLFQwtkmSfWEpRj_9OA0",[512,518,524,530,536,542,548,554,560,566,572,579,585,591,597,603,609,615,621,627,633,639,645,651,657,663,664,670,676,682,688,694,700,706,712,718,724,730,736,742,748,754,760,766,772,778,783,789,795,801,807,813,819,825,831,837,843,849,855,861,867,873,878,884,890,896,902,908,914,920,926,932,938,944,950,956,961,967,973,979,985,991,997,1003,1008,1014,1020,1026,1031,1037],{"path":513,"title":514,"description":515,"published":516,"category":468,"image":517,"draft":472},"\u002Fblog\u002Fmax-client-connections-reached","Supabase \"max client connections reached\", explicado","Supabase \"max client connections reached\": el pooler no tiene sitio para un cliente más. El puerto de tu cadena de conexión decide el límite.","2026-11-09","\u002Fblog\u002Fmax-client-connections-reached\u002Fcard-800x500.png",{"path":519,"title":520,"description":521,"published":522,"category":468,"image":523,"draft":472},"\u002Fblog\u002Funsupported-provider-provider-is-not-enabled","Error de Supabase: \"Unsupported provider: provider is not enabled\"","\"Unsupported provider: provider is not enabled\": Google está desactivado en tu proyecto Supabase. Cómo activarlo y arreglar redirect_uri_mismatch.","2026-11-08","\u002Fblog\u002Funsupported-provider-provider-is-not-enabled\u002Fcard-800x500.png",{"path":525,"title":526,"description":527,"published":528,"category":468,"image":529,"draft":472},"\u002Fblog\u002Fviolates-foreign-key-constraint","Error de Supabase \"violates foreign key constraint\" al insertar","Supabase \"insert or update on table violates foreign key constraint\": tu fila apunta a una fila que no existe. Cuál, por qué, y cómo arreglarlo.","2026-11-07","\u002Fblog\u002Fviolates-foreign-key-constraint\u002Fcard-800x500.png",{"path":531,"title":532,"description":533,"published":534,"category":468,"image":535,"draft":472},"\u002Fblog\u002Fnull-value-violates-not-null-constraint","Error de Supabase \"null value in column violates not-null constraint\"","Supabase \"null value in column violates not-null constraint\": una columna obligatoria llegó vacía. De dónde vino el null, y cómo arreglarlo.","2026-11-06","\u002Fblog\u002Fnull-value-violates-not-null-constraint\u002Fcard-800x500.png",{"path":537,"title":538,"description":539,"published":540,"category":468,"image":541,"draft":472},"\u002Fblog\u002Fauth-session-missing","Supabase \"Auth session missing!\": adónde fue la sesión","\"Auth session missing!\" es supabase-js sin encontrar ninguna sesión iniciada y sin llegar a preguntar a Supabase. Adónde fue la sesión, y el arreglo.","2026-11-05","\u002Fblog\u002Fauth-session-missing\u002Fcard-800x500.png",{"path":543,"title":544,"description":545,"published":546,"category":468,"image":547,"draft":472},"\u002Fblog\u002Finvalid-claim-missing-sub-claim","Supabase \"invalid claim: missing sub claim\": no hay nadie conectado","\"invalid claim: missing sub claim\": Supabase Auth recibió un token auténtico sin ningún usuario, la clave del proyecto en lugar de una sesión.","2026-11-04","\u002Fblog\u002Finvalid-claim-missing-sub-claim\u002Fcard-800x500.png",{"path":549,"title":550,"description":551,"published":552,"category":468,"image":553,"draft":472},"\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function","\"Failed to send a request to the Edge Function\": la causa real","\"Failed to send a request to the Edge Function\": el navegador no recibió una respuesta legible. Su consola dice por qué y si tu función se ejecutó.","2026-11-03","\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function\u002Fcard-800x500.png",{"path":555,"title":556,"description":557,"published":558,"category":468,"image":559,"draft":472},"\u002Fblog\u002Fsupabase-auth-redirects-to-localhost","Por qué los enlaces de email de Supabase redirigen a localhost:3000","Si Supabase redirige a localhost:3000, la Site URL nunca se cambió o tu dirección falta en Redirect URLs. La solución, y el comodín que debes evitar.","2026-11-02","\u002Fblog\u002Fsupabase-auth-redirects-to-localhost\u002Fcard-800x500.png",{"path":561,"title":562,"description":563,"published":564,"category":468,"image":565,"draft":472},"\u002Fblog\u002Femail-link-is-invalid-or-has-expired","Supabase \"Email link is invalid or has expired\" con un enlace nuevo","Con un enlace enviado hace un minuto, \"Email link is invalid or has expired\" en Supabase suele indicar que un filtro de correo lo usó antes. Cómo arreglarlo.","2026-11-01","\u002Fblog\u002Femail-link-is-invalid-or-has-expired\u002Fcard-800x500.png",{"path":567,"title":568,"description":569,"published":570,"category":468,"image":571,"draft":472},"\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout","Supabase \"canceling statement due to statement timeout\", explicado","Supabase \"canceling statement due to statement timeout\": una consulta superó el límite de su rol, 3 segundos para un visitante. Revisa antes la política RLS.","2026-10-31","\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout\u002Fcard-800x500.png",{"path":573,"title":574,"description":575,"published":576,"category":577,"image":578,"draft":472},"\u002Fblog\u002Fdatabase-error-deleting-user","\"Database error deleting user\" en Supabase, y qué se va con él","\"Database error deleting user\" en Supabase: tu base de datos rechazó el borrado. La causa está en tus logs y el arreglo decide qué más se borra.","2026-10-30","Backups","\u002Fblog\u002Fdatabase-error-deleting-user\u002Fcard-800x500.png",{"path":580,"title":581,"description":582,"published":583,"category":468,"image":584,"draft":472},"\u002Fblog\u002Fstripe-webhook-no-signatures-found","\"No signatures found matching the expected signature\" en Supabase","¿Tu webhook de Stripe en una Edge Function de Supabase dice \"No signatures found matching the expected signature\"? Tiene dos causas. Sigue verificando.","2026-10-29","\u002Fblog\u002Fstripe-webhook-no-signatures-found\u002Fcard-800x500.png",{"path":586,"title":587,"description":588,"published":589,"category":468,"image":590,"draft":472},"\u002Fblog\u002Fsupabase-invalid-login","\"Invalid login credentials\" en Supabase: las tres causas","Supabase dice \"Invalid login credentials\" ante una contraseña errónea, un email desconocido y una cuenta de Google. Cómo saber cuál es.","2026-10-28","\u002Fblog\u002Fsupabase-invalid-login\u002Fcard-800x500.png",{"path":592,"title":593,"description":594,"published":595,"category":468,"image":596,"draft":472},"\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code","\"Edge Function returned a non-2xx status code\": el error real","\"Edge Function returned a non-2xx status code\" significa que tu función de Supabase respondió con un error. Aquí ves dónde leer el real.","2026-10-27","\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code\u002Fcard-800x500.png",{"path":598,"title":599,"description":600,"published":601,"category":468,"image":602,"draft":472},"\u002Fblog\u002Fcertificate-not-trusted","Certificado no confiable: tres causas aparte de la caducidad","¿Certificado no confiable aunque la fecha está bien? Nombra otra dirección, se firmó a sí mismo o a su cadena le falta un eslabón. Cómo saber cuál.","2026-10-26","\u002Fblog\u002Fcertificate-not-trusted\u002Fcard-800x500.png",{"path":604,"title":605,"description":606,"published":607,"category":468,"image":608,"draft":472},"\u002Fblog\u002Finvalid-input-syntax-for-type-uuid","Supabase \"invalid input syntax for type uuid\": lee las comillas","Supabase \"invalid input syntax for type uuid\" significa que tu app envió algo que no es un id. Lee las comillas, frena la consulta, conserva la columna.","2026-10-25","\u002Fblog\u002Finvalid-input-syntax-for-type-uuid\u002Fcard-800x500.png",{"path":610,"title":611,"description":612,"published":613,"category":468,"image":614,"draft":472},"\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint","Supabase \"duplicate key value violates unique constraint\", explicado","Supabase \"duplicate key value violates unique constraint\": el valor ya está ocupado. Encuentra la columna, elige un arreglo y aparta el valor de la pantalla.","2026-10-24","\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint\u002Fcard-800x500.png",{"path":616,"title":617,"description":618,"published":619,"category":468,"image":620,"draft":472},"\u002Fblog\u002Fsupabase-relation-does-not-exist","Supabase \"relation does not exist\" aunque la tabla está ahí","Supabase \"relation does not exist\" o PGRST205: ninguna tabla tiene ese nombre en ese esquema. Cuatro comprobaciones, y lo que abre exponer un esquema.","2026-10-23","\u002Fblog\u002Fsupabase-relation-does-not-exist\u002Fcard-800x500.png",{"path":622,"title":623,"description":624,"published":625,"category":468,"image":626,"draft":472},"\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\" muestra los nombres de argumentos que envió tu app. Compáralos con la función.","2026-10-22","\u002Fblog\u002Fsupabase-function-not-found\u002Fcard-800x500.png",{"path":628,"title":629,"description":630,"published":631,"category":468,"image":632,"draft":472},"\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\" suele ser un nombre que no coincide. Cuatro comprobaciones y la línea que recarga.","2026-10-21","\u002Fblog\u002Fsupabase-schema-cache-column-error\u002Fcard-800x500.png",{"path":634,"title":635,"description":636,"published":637,"category":468,"image":638,"draft":472},"\u002Fblog\u002Fsupabase-email-rate-limit-exceeded","Supabase \"Email Rate Limit Exceeded\": dos límites, un solo código","Supabase \"Email Rate Limit Exceeded\" limita cada email que envía tu proyecto: 2 por hora con el remitente integrado. Qué cuenta y cómo subirlo.","2026-10-20","\u002Fblog\u002Fsupabase-email-rate-limit-exceeded\u002Fcard-800x500.png",{"path":640,"title":641,"description":642,"published":643,"category":468,"image":644,"draft":472},"\u002Fblog\u002Fsupabase-users-logged-out","Supabase \"Invalid Refresh Token: Refresh Token Not Found\": 3 causas","Supabase \"Invalid Refresh Token: Refresh Token Not Found\" cierra la sesión de tus usuarios. Tres causas, y cómo las separa el log de Auth.","2026-10-19","\u002Fblog\u002Fsupabase-users-logged-out\u002Fcard-800x500.png",{"path":646,"title":647,"description":648,"published":649,"category":468,"image":650,"draft":472},"\u002Fblog\u002Fpermission-denied-for-schema-public","Supabase \"permission denied for schema public\": tres causas","Supabase \"permission denied for schema public\" es un grant que falta en el esquema. Qué lo quitó y la línea que lo devuelve.","2026-10-18","\u002Fblog\u002Fpermission-denied-for-schema-public\u002Fcard-800x500.png",{"path":652,"title":653,"description":654,"published":655,"category":468,"image":656,"draft":472},"\u002Fblog\u002Fsupabase-bucket-not-found","Supabase \"Bucket not found\": las tres cosas que significa","Supabase \"Bucket not found\" es una de tres cosas: un enlace público a un bucket privado, un nombre que no coincide exactamente o el proyecto equivocado.","2026-10-17","\u002Fblog\u002Fsupabase-bucket-not-found\u002Fcard-800x500.png",{"path":658,"title":659,"description":660,"published":661,"category":468,"image":662,"draft":472},"\u002Fblog\u002Fsupabase-invalid-jwt","Supabase invalid JWT: ¿qué clave dejó de funcionar?","Un error Supabase invalid JWT es PGRST301: un token firmado no pasó la verificación. En un proyecto nuevo se trata de la sesión, no de la clave de API.","2026-10-16","\u002Fblog\u002Fsupabase-invalid-jwt\u002Fcard-800x500.png",{"path":502,"title":5,"description":471,"published":503,"category":468,"image":490,"draft":472},{"path":665,"title":666,"description":667,"published":668,"category":468,"image":669,"draft":472},"\u002Fblog\u002Fdatabase-error-saving-new-user","\"Database error saving new user\" en Supabase: dónde mirar","\"Database error saving new user\" significa que algo unido a tu registro de Supabase falló y se deshizo entero. El error real está en tus logs.","2026-10-14","\u002Fblog\u002Fdatabase-error-saving-new-user\u002Fcard-800x500.png",{"path":671,"title":672,"description":673,"published":674,"category":468,"image":675,"draft":472},"\u002Fblog\u002Fwhat-is-supabase","¿Qué es Supabase? La base de datos que eligió tu builder","Qué es Supabase: la base de datos, el login y el almacenamiento de archivos de tu app. Supabase lleva los servidores; las reglas sobre tus filas son tuyas.","2026-10-13","\u002Fblog\u002Fwhat-is-supabase\u002Fcard-800x500.png",{"path":677,"title":678,"description":679,"published":680,"category":468,"image":681,"draft":472},"\u002Fblog\u002Faws-access-key-exposed-in-frontend","Una clave AWS expuesta en tu frontend no es como una clave OpenAI","Una clave de acceso de AWS expuesta en tu frontend lee y escribe tu almacenamiento. La solución suele ser una presigned URL, no una clave nueva.","2026-10-12","\u002Fblog\u002Faws-access-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":683,"title":684,"description":685,"published":686,"category":468,"image":687,"draft":472},"\u002Fblog\u002Fstorage-upload-violates-row-level-security","\"Row-level security policy for table objects\" al subir","\"New row violates row-level security policy for table objects\" significa que tu subida no tiene regla insert. Hacer público el bucket no añade ninguna.","2026-10-11","\u002Fblog\u002Fstorage-upload-violates-row-level-security\u002Fcard-800x500.png",{"path":689,"title":690,"description":691,"published":692,"category":468,"image":693,"draft":472},"\u002Fblog\u002Fbase44-security-scan","Escaneo de seguridad de Base44: lo que solo él ve","El escaneo de seguridad de Base44 revisa siete tipos de problema desde dentro. Esta es la mitad que lee y nadie más puede leer, y la mitad que nunca mira.","2026-10-10","\u002Fblog\u002Fbase44-security-scan\u002Fcard-800x500.png",{"path":695,"title":696,"description":697,"published":698,"category":468,"image":699,"draft":472},"\u002Fblog\u002Fapi-key-leaked-what-to-do","Tu clave API se filtró. El orden en el que hay que actuar","Una clave API se filtró y no sabes por dónde empezar. No todas las claves de tu frontend lo son, y el orden importa más que la velocidad.","2026-10-09","\u002Fblog\u002Fapi-key-leaked-what-to-do\u002Fcard-800x500.png",{"path":701,"title":702,"description":703,"published":704,"category":468,"image":705,"draft":472},"\u002Fblog\u002Finfinite-recursion-in-policy-for-relation","\"Infinite recursion detected in policy\" sin desactivar RLS","\"Infinite recursion detected in policy for relation\" significa que tu policy preguntó a la tabla que protege. Así se rompe el círculo.","2026-10-08","\u002Fblog\u002Finfinite-recursion-in-policy-for-relation\u002Fcard-800x500.png",{"path":707,"title":708,"description":709,"published":710,"category":468,"image":711,"draft":472},"\u002Fblog\u002Fno-api-key-found-in-request","\"No API key found in request\" en Supabase, y el arreglo equivocado","\"No API key found in request\" significa que tu petición llegó a Supabase sin clave. Casi todas las respuestas apuntan a las reglas de tu base de datos.","2026-10-07","\u002Fblog\u002Fno-api-key-found-in-request\u002Fcard-800x500.png",{"path":713,"title":714,"description":715,"published":716,"category":468,"image":717,"draft":472},"\u002Fblog\u002Fis-base44-safe","¿Es seguro Base44? Lo que vimos en 5.442 apps Base44","¿Es seguro Base44? Pasamos nueve comprobaciones a 5.442 apps Base44 en producción. Casi todas sacaron B por motivos que su dueño nunca eligió.","2026-10-06","\u002Fblog\u002Fis-base44-safe\u002Fcard-800x500.png",{"path":719,"title":720,"description":721,"published":722,"category":468,"image":723,"draft":472},"\u002Fblog\u002Fmove-a-secret-to-an-edge-function","Ocultar una clave API: muévela a una Edge Function de Supabase","Ocultar una clave API significa sacarla del navegador, y una Edge Function de Supabase es el sitio más pequeño donde ponerla. Dos pasos importan más.","2026-10-05","\u002Fblog\u002Fmove-a-secret-to-an-edge-function\u002Fcard-800x500.png",{"path":725,"title":726,"description":727,"published":728,"category":468,"image":729,"draft":472},"\u002Fblog\u002Fenv-file-exposed-on-your-server","¿Tu archivo .env está expuesto? Las doce rutas a revisar","¿Tu archivo .env está expuesto en tu propio servidor web? Doce direcciones te lo dicen, y un acierto significa que todo lo que contiene ya es público.","2026-10-04","\u002Fblog\u002Fenv-file-exposed-on-your-server\u002Fcard-800x500.png",{"path":731,"title":732,"description":733,"published":734,"category":468,"image":735,"draft":472},"\u002Fblog\u002Fis-v0-safe","Seguridad de v0: las 1.790 aplicaciones escaneadas sacaron una A","Seguridad de v0, medida en 1.790 aplicaciones v0 en vivo: todas sacaron A. Solo 17 nombraban una base de datos, y eso es casi todo lo que mide la A.","2026-10-03","\u002Fblog\u002Fis-v0-safe\u002Fcard-800x500.png",{"path":737,"title":738,"description":739,"published":740,"category":468,"image":741,"draft":472},"\u002Fblog\u002Fis-bolt-safe","¿Es seguro Bolt? Lo que vimos en 1.123 aplicaciones Bolt","¿Es seguro Bolt? Pasamos 1.123 aplicaciones Bolt en vivo por nueve comprobaciones. El hosting salió limpio. Los hallazgos eran claves y tablas abiertas dentro.","2026-10-02","\u002Fblog\u002Fis-bolt-safe\u002Fcard-800x500.png",{"path":743,"title":744,"description":745,"published":746,"category":468,"image":747,"draft":472},"\u002Fblog\u002Fis-supabase-down-or-your-app","¿Supabase está caído o es tu app? Cómo distinguirlo","¿Supabase está caído o es tu app? Un proyecto pausado, una base de datos llena y un fallo tuyo parecen lo mismo. Cuatro comprobaciones los separan.","2026-10-01","\u002Fblog\u002Fis-supabase-down-or-your-app\u002Fcard-800x500.png",{"path":749,"title":750,"description":751,"published":752,"category":468,"image":753,"draft":472},"\u002Fblog\u002Fdoes-supabase-encrypt-my-data","¿Supabase cifra mis datos? Sí. Esto es lo que detiene","¿Supabase cifra los datos? Sí: AES-256 en reposo, TLS en tránsito, SOC 2 e ISO 27001. Qué cubre cada uno, y la fuga que ninguno de ellos detiene.","2026-09-30","\u002Fblog\u002Fdoes-supabase-encrypt-my-data\u002Fcard-800x500.png",{"path":755,"title":756,"description":757,"published":758,"category":468,"image":759,"draft":472},"\u002Fblog\u002Fsupabase-free-plan-limits","¿Cuánto cuesta Supabase? Los límites del plan gratuito","Los límites del plan gratuito de Supabase: 500 MB de base de datos, 5 GB de egress y ningún backup. Qué pasa en cada uno y qué cambia Pro por $25.","2026-09-29","\u002Fblog\u002Fsupabase-free-plan-limits\u002Fcard-800x500.png",{"path":761,"title":762,"description":763,"published":764,"category":577,"image":765,"draft":472},"\u002Fblog\u002Ftest-your-supabase-backup","Prueba tu backup de Supabase antes del día que lo necesites","Cómo probar tu backup de Supabase: restaurarlo en un proyecto de prueba, contar filas, iniciar sesión y buscar la línea que le falta a un archivo cortado.","2026-09-28","\u002Fblog\u002Ftest-your-supabase-backup\u002Fcard-800x500.png",{"path":767,"title":768,"description":769,"published":770,"category":577,"image":771,"draft":472},"\u002Fblog\u002Fsupabase-backup-github-action","Backup gratis de Supabase con una GitHub Action, y la trampa","Un backup de Supabase con GitHub Action es gratis y sirve a muchas apps. El workflow, el connection string correcto y el egress de cada ejecución.","2026-09-27","\u002Fblog\u002Fsupabase-backup-github-action\u002Fcard-800x500.png",{"path":773,"title":774,"description":775,"published":776,"category":577,"image":777,"draft":472},"\u002Fblog\u002Fdownload-your-supabase-backup","Por qué no puedes descargar tu backup de Supabase","No puedes descargar tu backup de Supabase en un proyecto actual: la copia diaria es una instantánea física. Cómo comprobarlo y tener tu propia copia.","2026-09-26","\u002Fblog\u002Fdownload-your-supabase-backup\u002Fcard-800x500.png",{"path":779,"title":780,"description":781,"published":776,"category":468,"image":782,"draft":472},"\u002Fblog\u002Fsupabase-permission-denied-for-table","Supabase \"permission denied for table\": el grant que falta","Desde el 30 de octubre, una tabla nueva de Supabase responde \"permission denied for table\" hasta que le das acceso. El grant del email es la mitad del arreglo.","\u002Fblog\u002Fsupabase-permission-denied-for-table\u002Fcard-800x500.png",{"path":784,"title":785,"description":786,"published":787,"category":468,"image":788,"draft":472},"\u002Fblog\u002Fopen-api-endpoint-exposed","¿Un endpoint de API abierto es un problema? Mira el JSON","Tu escaneo señaló un endpoint de API abierto. Que importe depende de lo que devolvió, y la mayoría de los que encontramos eran de la plataforma.","2026-09-25","\u002Fblog\u002Fopen-api-endpoint-exposed\u002Fcard-800x500.png",{"path":790,"title":791,"description":792,"published":793,"category":468,"image":794,"draft":472},"\u002Fblog\u002Flovable-security-scan","Escaneo de seguridad de Lovable: lo que no puede probar","Escaneo de seguridad de Lovable: qué revisan el Quick scan y el Deep scan, cuándo corre cada uno, y lo único que ningún escaneo desde dentro puede probar.","2026-09-24","\u002Fblog\u002Flovable-security-scan\u002Fcard-800x500.png",{"path":796,"title":797,"description":798,"published":799,"category":577,"image":800,"draft":472},"\u002Fblog\u002Fsupabase-backup-auth-users","Por qué tu dump de Supabase no tiene usuarios dentro","Ejecuta supabase db dump por sí solo y obtienes la forma de tu base de datos y ninguna de sus filas, sin el esquema auth donde viven tus usuarios.","2026-09-23","\u002Fblog\u002Fsupabase-backup-auth-users\u002Fcard-800x500.png",{"path":802,"title":803,"description":804,"published":805,"category":468,"image":806,"draft":472},"\u002Fblog\u002Fdomain-and-certificate-expiry","Dominio caducado, web caída: qué pasa a partir de ahora","Tu dominio caducó y tu web está caída. Aquí tienes el reloj que acaba de arrancar, por qué el certificado es el menor problema, y cómo comprobar ambos.","2026-09-22","\u002Fblog\u002Fdomain-and-certificate-expiry\u002Fcard-800x500.png",{"path":808,"title":809,"description":810,"published":811,"category":468,"image":812,"draft":472},"\u002Fblog\u002Fis-lovable-safe","¿Es seguro Lovable? Lo que vimos en 18.554 aplicaciones Lovable","¿Es seguro Lovable? Pasamos 18.554 aplicaciones Lovable por nueve comprobaciones. La plataforma fue la más limpia de cinco. Los hallazgos estaban dentro.","2026-09-21","\u002Fblog\u002Fis-lovable-safe\u002Fcard-800x500.png",{"path":814,"title":815,"description":816,"published":817,"category":468,"image":818,"draft":472},"\u002Fblog\u002Fvibe-coded-app-security-checklist","La lista de seguridad del vibe coding, en nueve comprobaciones","Una lista de seguridad del vibe coding con nueve puntos, cada uno verificable en tu app desde fuera por cualquiera, y cada uno con una prueba de una línea.","2026-09-20","\u002Fblog\u002Fvibe-coded-app-security-checklist\u002Fcard-800x500.png",{"path":820,"title":821,"description":822,"published":823,"category":468,"image":824,"draft":472},"\u002Fblog\u002Fstripe-secret-key-in-frontend","Una clave secreta de Stripe en tu frontend puede mover dinero","Una clave secreta de Stripe expuesta en tu frontend puede reembolsar, cobrar y leer cada ficha de cliente que tienes. Tu clave pk_live_ sí debe estar ahí.","2026-09-19","\u002Fblog\u002Fstripe-secret-key-in-frontend\u002Fcard-800x500.png",{"path":826,"title":827,"description":828,"published":829,"category":468,"image":830,"draft":472},"\u002Fblog\u002Fvite-and-next-public-env-vars","Variables de entorno de Vite expuestas: el prefijo dice publica esto","Variables de entorno de Vite expuestas en tu app: hicieron lo que pedía el prefijo. VITE_ y NEXT_PUBLIC_ significan publica esto, y la IA nunca supo el coste.","2026-09-18","\u002Fblog\u002Fvite-and-next-public-env-vars\u002Fcard-800x500.png",{"path":832,"title":833,"description":834,"published":835,"category":468,"image":836,"draft":472},"\u002Fblog\u002Fbase44-source-maps","Seguridad en Base44: qué marca un escaneo y qué te toca arreglar a ti","Seguridad en Base44 en 5.438 apps escaneadas: tres hallazgos en casi todas son de la plataforma, el source map es la insignia de Base44 y lo tuyo es poco.","2026-09-17","\u002Fblog\u002Fbase44-source-maps\u002Fcard-800x500.png",{"path":838,"title":839,"description":840,"published":841,"category":468,"image":842,"draft":472},"\u002Fblog\u002Fis-cursor-ai-safe","¿Es seguro Cursor AI? El editor, el código y la app que publicaste","¿Es seguro Cursor AI? Tres preguntas en una búsqueda: qué guarda Cursor, en qué falla el código que escribe y si la app que publicaste está abierta.","2026-09-16","\u002Fblog\u002Fis-cursor-ai-safe\u002Fcard-800x500.png",{"path":844,"title":845,"description":846,"published":847,"category":468,"image":848,"draft":472},"\u002Fblog\u002Fis-replit-safe","¿Es seguro Replit? Lo que vimos en 3.042 aplicaciones Replit en vivo","¿Es seguro Replit? Pasamos 3.042 aplicaciones Replit en vivo por nueve comprobaciones externas. Los hallazgos estaban en la aplicación publicada, no en el host.","2026-09-15","\u002Fblog\u002Fis-replit-safe\u002Fcard-800x500.png",{"path":850,"title":851,"description":852,"published":853,"category":577,"image":854,"draft":472},"\u002Fblog\u002Fsupabase-storage-backup","Supabase storage backup: tu copia de la base no tiene archivos","Un Supabase storage backup es una tarea aparte. Las copias de la base guardan la lista de tus archivos y ninguno de ellos, así que cada upload queda roto.","2026-09-14","\u002Fblog\u002Fsupabase-storage-backup\u002Fcard-800x500.png",{"path":856,"title":857,"description":858,"published":859,"category":577,"image":860,"draft":472},"\u002Fblog\u002Fsupabase-point-in-time-recovery","Point-in-time recovery de Supabase: precio y límites","El point-in-time recovery de Supabase rebobina tu base de datos a cualquier segundo de la última semana. Cuesta $100 al mes sobre Pro y solo cubre la base.","2026-09-13","\u002Fblog\u002Fsupabase-point-in-time-recovery\u002Fcard-800x500.png",{"path":862,"title":863,"description":864,"published":865,"category":577,"image":866,"draft":472},"\u002Fblog\u002Fsupabase-project-paused-recover","¿Proyecto de Supabase pausado? Tus datos siguen ahí","Supabase pausó tu proyecto tras una semana sin actividad. No se ha borrado nada, Restaurar está junto al nombre y tienes un año antes de que eso cambie.","2026-09-12","\u002Fblog\u002Fsupabase-project-paused-recover\u002Fcard-800x500.png",{"path":868,"title":869,"description":870,"published":871,"category":468,"image":872,"draft":472},"\u002Fblog\u002Fsafest-ai-app-builder","¿Qué builder de apps con IA es más seguro? 30.998 apps escaneadas","¿Qué builder de apps con IA es más seguro? Escaneamos 30.998 apps activas de Lovable, Base44, Replit, v0 y Bolt. El builder no es lo que decide tu nota.","2026-09-11","\u002Fblog\u002Fsafest-ai-app-builder\u002Fcard-800x500.png",{"path":446,"title":874,"description":875,"published":876,"category":468,"image":877,"draft":472},"Activa Row Level Security en cada tabla de Supabase y compruébalo","Activar Row Level Security en Supabase sin política cierra la tabla del todo. Una política sin el interruptor no hace nada. Aquí tienes el SQL y la prueba.","2026-09-10","\u002Fblog\u002Fenable-rls-on-every-supabase-table\u002Fcard-800x500.png",{"path":879,"title":880,"description":881,"published":882,"category":468,"image":883,"draft":472},"\u002Fblog\u002Fsupabase-rls-disabled-in-public","Supabase \"RLS disabled in public\": lo que el aviso no ve","Supabase marca \"RLS disabled in public\" como error. No dice nada de la política de lectura que deja tu tabla igual de abierta a cualquiera.","2026-09-09","\u002Fblog\u002Fsupabase-rls-disabled-in-public\u002Fcard-800x500.png",{"path":885,"title":886,"description":887,"published":888,"category":468,"image":889,"draft":472},"\u002Fblog\u002Frotate-supabase-service-role-key","Cómo rotar una clave service_role de Supabase filtrada","Supabase dice que primero cierres la fuga. Otras guías dicen que rotes ya. Cuál es lo correcto depende de dónde se filtró tu clave service_role.","2026-09-08","\u002Fblog\u002Frotate-supabase-service-role-key\u002Fcard-800x500.png",{"path":891,"title":892,"description":893,"published":894,"category":468,"image":895,"draft":472},"\u002Fblog\u002Fvibe-coding-security-scanners-compared","Escáneres de seguridad vibe coding comparados, el nuestro incluido","El mejor escáner de seguridad para vibe coding depende de tres preguntas que ninguna lista de funciones responde. Ocho herramientas, con precios.","2026-09-07","\u002Fblog\u002Fvibe-coding-security-scanners-compared\u002Fcard-800x500.png",{"path":897,"title":898,"description":899,"published":900,"category":468,"image":901,"draft":472},"\u002Fblog\u002Fsupabase-security-checker","Supabase security checker: haz tú mismo las cinco comprobaciones","Un Supabase security checker lee tu app publicada en lugar de la configuración de tu proyecto. Estas son las cinco comprobaciones y cómo hacer cada una.","2026-09-06","\u002Fblog\u002Fsupabase-security-checker\u002Fcard-800x500.png",{"path":903,"title":904,"description":905,"published":906,"category":468,"image":907,"draft":472},"\u002Fblog\u002Fvibe-coding-security-scanner","Escáner de seguridad para vibe coding: qué se le escapa","Un escáner de seguridad para vibe coding lee tu app en vivo desde fuera. Qué cubre eso, las cuatro cosas que no puede ver y cómo leer el resultado.","2026-09-05","\u002Fblog\u002Fvibe-coding-security-scanner\u002Fcard-800x500.png",{"path":909,"title":910,"description":911,"published":912,"category":468,"image":913,"draft":472},"\u002Fblog\u002Fmissing-security-headers","Faltan cabeceras de seguridad: cuándo importa de verdad","Que falten cabeceras de seguridad es el hallazgo que más imprime nuestro escáner. Contra qué protegen y cuándo son la línea menos urgente de tu informe.","2026-09-04","\u002Fblog\u002Fmissing-security-headers\u002Fcard-800x500.png",{"path":915,"title":916,"description":917,"published":918,"category":468,"image":919,"draft":472},"\u002Fblog\u002Fopenai-api-key-exposed-in-frontend","Tu clave de API de OpenAI está expuesta en tu frontend. Rótala.","Una clave de API de OpenAI expuesta en tu frontend no se puede atar a un dominio. Rótala hoy, mueve la llamada a tu servidor y limita el gasto.","2026-09-03","\u002Fblog\u002Fopenai-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":921,"title":922,"description":923,"published":924,"category":468,"image":925,"draft":472},"\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps","Clave de API expuesta en el frontend: qué llevan 30.998 apps","Una clave de API expuesta en tu frontend suele ser una clave de Google Maps. Escaneamos 30.998 apps vibe-coded y contamos qué secretos se filtran de verdad.","2026-09-02","\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps\u002Fcard-800x500.png",{"path":927,"title":928,"description":929,"published":930,"category":577,"image":931,"draft":472},"\u002Fblog\u002Fsupabase-backup-tools-compared","Herramientas de backup de Supabase comparadas, la nuestra incluida","Cuatro tipos de herramienta de backup de Supabase, qué copia cada una y cuándo una GitHub Action gratuita le gana a pagar a cualquiera, nosotros incluidos.","2026-09-01","\u002Fblog\u002Fsupabase-backup-tools-compared\u002Fcard-800x500.png",{"path":933,"title":934,"description":935,"published":936,"category":468,"image":937,"draft":472},"\u002Fblog\u002Freplit-secrets-explained","Cómo usar secrets en Replit, y qué se publica de todos modos","Cómo usar secrets en Replit: añadir uno, leerlo y arreglar las dos causas del undefined. Y las claves que la herramienta Secrets no puede mantener privadas.","2026-08-31","\u002Fblog\u002Freplit-secrets-explained\u002Fcard-800x500.png",{"path":939,"title":940,"description":941,"published":942,"category":577,"image":943,"draft":472},"\u002Fblog\u002Fback-up-supabase-free-tier","Backups del plan gratuito de Supabase: cómo hacer uno sin terminal","No hay backups en el plan gratuito de Supabase: la copia tienes que hacerla tú. Cómo sacarla desde el panel y qué deja fuera la vía CSV.","2026-08-30","\u002Fblog\u002Fback-up-supabase-free-tier\u002Fcard-800x500.png",{"path":945,"title":946,"description":947,"published":948,"category":468,"image":949,"draft":472},"\u002Fblog\u002Fis-supabase-secure","¿Supabase es seguro? Sí. Tu proyecto es otra pregunta","¿Supabase es seguro? La plataforma está auditada, cifrada y sometida a pentests. Su propia documentación dice dónde termina eso y empiezan tus ajustes.","2026-08-29","\u002Fblog\u002Fis-supabase-secure\u002Fcard-800x500.png",{"path":951,"title":952,"description":953,"published":954,"category":468,"image":955,"draft":472},"\u002Fblog\u002Fwhere-to-find-supabase-api-keys","Dónde están tus claves API de Supabase: anon, service_role y URL","La URL del proyecto, la clave anon y la clave service_role están en una sola página del panel. Aquí tienes dónde está, y cuál de los cuatro va en tu app.","2026-08-28","\u002Fblog\u002Fwhere-to-find-supabase-api-keys\u002Fcard-800x500.png",{"path":451,"title":957,"description":958,"published":959,"category":468,"image":960,"draft":472},"New row violates row-level security policy en Supabase. ¿Y ahora?","\"New row violates row-level security policy\" significa que Supabase rechazó una escritura. El arreglo rápido vuelve a abrir la tabla para cualquiera.","2026-08-27","\u002Fblog\u002Fnew-row-violates-row-level-security-policy\u002Fcard-800x500.png",{"path":962,"title":963,"description":964,"published":965,"category":468,"image":966,"draft":472},"\u002Fblog\u002Fcors-wildcard-security-risk","¿Es un comodín CORS un riesgo de seguridad? Casi nunca.","¿Es un comodín CORS un riesgo de seguridad? Casi siempre es el ajuste por defecto de tu builder y no entrega nada que tu servidor no diera ya a cualquiera.","2026-08-26","\u002Fblog\u002Fcors-wildcard-security-risk\u002Fcard-800x500.png",{"path":968,"title":969,"description":970,"published":971,"category":577,"image":972,"draft":472},"\u002Fblog\u002Fsupabase-branching-is-not-a-backup","Supabase branching no es un backup. Solo va hacia adelante.","Por qué el branching de Supabase no es un backup: una rama arranca sin tus datos y un merge solo mueve el esquema. Para qué sirve y qué usar en su lugar.","2026-08-25","\u002Fblog\u002Fsupabase-branching-is-not-a-backup\u002Fcard-800x500.png",{"path":974,"title":975,"description":976,"published":977,"category":577,"image":978,"draft":472},"\u002Fblog\u002Fhow-to-restore-a-supabase-backup","Cómo restaurar un backup de Supabase, y qué se rompe después","Cómo restaurar un backup de Supabase desde el panel o desde un archivo de volcado, qué reemplaza la restauración y por qué tu app puede seguir rota al terminar.","2026-08-24","\u002Fblog\u002Fhow-to-restore-a-supabase-backup\u002Fcard-800x500.png",{"path":980,"title":981,"description":982,"published":983,"category":468,"image":984,"draft":472},"\u002Fblog\u002Fsupabase-storage-bucket-public","Tu bucket de Supabase Storage es público. ¿Es un problema?","Un bucket público de Supabase Storage significa que quien tenga la URL de un archivo puede abrirlo. No significa que alguien pueda listar lo que hay dentro.","2026-08-23","\u002Fblog\u002Fsupabase-storage-bucket-public\u002Fcard-800x500.png",{"path":986,"title":987,"description":988,"published":989,"category":468,"image":990,"draft":472},"\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend","¿Es un problema una clave de API de Google en tu frontend?","Una clave de API de Google en tu frontend es la clave que más encuentra nuestro escáner, y casi siempre no pasa nada. Un ajuste gratuito decide cuál es cuál.","2026-08-22","\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":992,"title":993,"description":994,"published":995,"category":577,"image":996,"draft":472},"\u002Fblog\u002Fai-agent-deleted-my-database","Un agente de IA borró mis datos de Supabase. ¿Qué puedo recuperar?","Un agente de IA borró datos de tu base. Lo que puedes recuperar ya estaba decidido antes de que se ejecutara, y los próximos minutos deciden el resto.","2026-08-21","\u002Fblog\u002Fai-agent-deleted-my-database\u002Fcard-800x500.png",{"path":998,"title":999,"description":1000,"published":1001,"category":468,"image":1002,"draft":472},"\u002Fblog\u002Fcan-anyone-read-your-supabase-database","¿Puede cualquiera leer tu base de datos Supabase? 3.680 apps","¿Puede cualquiera leer tu base de datos Supabase sin iniciar sesión? Escaneamos 30.998 apps activas hechas con builders de IA y medimos cuántas dicen que sí.","2026-08-18","\u002Fblog\u002Fcan-anyone-read-your-supabase-database\u002Fcard-800x500.png",{"path":1004,"title":1005,"description":1006,"published":1001,"category":468,"image":1007,"draft":472},"\u002Fblog\u002Fsource-maps-exposed-in-production","Source maps expuestos: tu app está publicando su código original","Un source map expuesto deja que cualquiera lea el código original de tu app, comentarios incluidos. La comprobación de 30 segundos y lo que de verdad importa.","\u002Fblog\u002Fsource-maps-exposed-in-production\u002Fcard-800x500.png",{"path":1009,"title":1010,"description":1011,"published":1012,"category":468,"image":1013,"draft":472},"\u002Fblog\u002Fsupabase-new-api-keys","Supabase publishable key: ¿es la misma que la anon key?","Supabase sustituyó anon y service_role por claves publicables y secretas. ¿Cuál pertenece a tu app y cuál no debe estar nunca?","2026-08-12","\u002Fblog\u002Fsupabase-new-api-keys\u002Fcard-800x500.png",{"path":1015,"title":1016,"description":1017,"published":1018,"category":577,"image":1019,"draft":472},"\u002Fblog\u002Fdoes-supabase-back-up-my-database","¿Supabase respalda mi base de datos? Depende de tu plan.","¿Supabase respalda tu base de datos? A diario en los planes de pago, y nada en el gratuito. Cómo saber cuál tienes y qué es lo que esa copia no cubre.","2026-08-11","\u002Fblog\u002Fdoes-supabase-back-up-my-database\u002Fcard-800x500.png",{"path":1021,"title":1022,"description":1023,"published":1024,"category":468,"image":1025,"draft":472},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","Supabase Row Level Security está activado. Tu tabla sigue pública.","Activar Supabase Row Level Security no protege una tabla. Lo hacen tus políticas, y la que arregló tu app rota puede dejar entrar a cualquiera.","2026-08-10","\u002Fblog\u002Fsupabase-rls-on-but-table-still-public\u002Fcard-800x500.png",{"path":1027,"title":1028,"description":1029,"published":1024,"category":577,"image":1030,"draft":472},"\u002Fblog\u002Fversion-history-is-not-a-backup","El historial de versiones no es un backup. No recupera una tabla.","Lovable y Bolt guardan un historial de versiones de tu código. Tu base de datos es un servicio aparte, y volver atrás no te devuelve tus datos.","\u002Fblog\u002Fversion-history-is-not-a-backup\u002Fcard-800x500.png",{"path":1032,"title":1033,"description":1034,"published":1035,"category":577,"image":1036,"draft":472},"\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database","Tres formas de respaldar una base Supabase, y qué falta en cada una","El panel, pg_dump y un servicio gestionado. Qué guarda de verdad cada uno, qué deja fuera sin avisar y cuál sobrevive a perder la cuenta.","2026-08-09","\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database\u002Fcard-800x500.png",{"path":1038,"title":1039,"description":1040,"published":1035,"category":468,"image":1041,"draft":472},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","Qué claves de API son seguras en el navegador y cuáles no","Tu clave anon de Supabase está pensada para ser pública. Tu clave service_role no, y se salta todas las reglas que pongas. Cómo distinguirlas.","\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend\u002Fcard-800x500.png",1794213645224]