[{"data":1,"prerenderedAt":990},["ShallowReactive",2],{"blog-es-supabase-bucket-not-found":3,"blog-index-es":459},{"id":4,"title":5,"body":6,"category":416,"cover":417,"coverAlt":418,"description":419,"draft":420,"extension":421,"faq":422,"image":438,"keywords":439,"meta":447,"navigation":448,"ogTitle":5,"path":449,"published":450,"seo":451,"stem":452,"tldr":453,"updated":450,"__hash__":458},"blog_es\u002Fblog\u002Fsupabase-bucket-not-found.md","Supabase \"Bucket not found\": las tres cosas que significa",{"type":7,"value":8,"toc":403},"minimark",[9,13,16,27,30,38,43,46,49,75,78,100,104,107,112,118,121,132,135,141,145,163,166,169,175,179,182,191,194,209,214,218,221,224,227,238,242,245,255,269,272,276,279,291,298,302,305,314,332,341,358,362,390],[10,11,12],"p",{},"Tu app muestra una imagen rota donde debería haber una foto. O falla una subida,\ny el mensaje que vuelve tiene tres palabras: \"Bucket not found\". Entonces abres\nSupabase, vas a Storage y el bucket está ahí mismo, en la lista.",[10,14,15],{},"Abre la dirección de la imagen en una pestaña aparte y Storage responde esto:",[17,18,23],"pre",{"className":19,"code":21,"language":22},[20],"language-text","{\n  \"statusCode\": \"404\",\n  \"code\": \"NoSuchBucket\",\n  \"error\": \"Bucket not found\",\n  \"message\": \"Bucket not found\"\n}\n","text",[24,25,21],"code",{"__ignoreMap":26},"",[10,28,29],{},"Ese es el cuerpo que construye hoy el código fuente de Supabase Storage, leído\nel 17 de octubre de 2026. Supabase \"Bucket not found\" cubre tres situaciones\ndistintas con ese mismo cuerpo, y en la primera el bucket está exactamente donde\nlo dejaste.",[10,31,32,33,37],{},"Y aquí es donde guía tras guía se equivoca: ",[34,35,36],"strong",{},"la primera solución que vas a\nencontrar es hacer público el bucket, y cuando funciona, funciona porque cada\narchivo de ese bucket pasa a ser público también."," Para dos de las tres causas\nno cambia absolutamente nada. Para la que queda, cambia una imagen rota por un\nbucket que puede leer cualquiera que tenga la dirección de un archivo.",[39,40,42],"h2",{"id":41},"qué-significa-supabase-bucket-not-found","¿Qué significa Supabase \"Bucket not found\"?",[10,44,45],{},"Storage buscó un bucket con exactamente el nombre de tu petición, dentro del\nproyecto al que llegó tu petición, y no encontró ninguno que estuviera dispuesto\na servir a esa petición.",[10,47,48],{},"Esa última parte está ahí porque un bucket tiene más de una puerta, y cada\npuerta hace la pregunta a su manera. El código fuente de Storage muestra tres:",[50,51,52,63,69],"ul",{},[53,54,55,58,59,62],"li",{},[34,56,57],{},"Una dirección pública de archivo",", la que genera ",[24,60,61],{},"getPublicUrl",". Esta\npuerta solo cuenta los buckets marcados como públicos, así que un bucket\nprivado aparece aquí como \"no encontrado\" aunque exista.",[53,64,65,68],{},[34,66,67],{},"Una subida."," Esta puerta cuenta todos los buckets del proyecto, privados\nincluidos. \"No encontrado\" significa aquí que ese nombre de verdad no existe\nen ese proyecto.",[53,70,71,74],{},[34,72,73],{},"Una petición de la lista de archivos de un bucket."," Esta puerta nunca dice\n\"Bucket not found\". Un bucket que no existe responde con una lista vacía, la\nmisma respuesta que da un bucket vacío, y eso lo vemos desde fuera cada vez\nque pregunta nuestro escáner.",[10,76,77],{},"Así que lo primero es averiguar por qué puerta entró la petición que falló.",[10,79,80,83,84,87,88,91,92,95,96,99],{},[34,81,82],{},"Los dos números de ese mensaje no coinciden, y eso confunde el manejo de\nerrores."," El cuerpo dice ",[24,85,86],{},"\"statusCode\": \"404\"",", mientras que la petición en sí\nfalla con el estado HTTP 400. Storage envía este error con un 400 y guarda su\npropio 404 dentro del cuerpo. La librería supabase-js pasa los dos a tu código:\n",[24,89,90],{},"error.status"," es 400 y ",[24,93,94],{},"error.statusCode"," es ",[24,97,98],{},"\"404\"",". El código que tu builder\nescribió para atrapar un 404 dejará pasar este.",[39,101,103],{"id":102},"causa-1-un-enlace-público-a-un-bucket-privado","Causa 1: un enlace público a un bucket privado",[10,105,106],{},"Esta es la causa de las imágenes rotas. La dirección se construyó para un bucket\npúblico, y el bucket es privado.",[10,108,109,111],{},[24,110,61],{}," no le pregunta nada a Supabase. Junta la dirección de tu\nproyecto, el nombre del bucket y el nombre del archivo en un enlace, dentro de tu\napp, y te lo devuelve. La nota que hay encima de esa función, en la propia\nlibrería cliente de Supabase, lo dice en dos frases:",[113,114,115],"blockquote",{},[10,116,117],{},"Esta función no comprueba si el bucket es público. Si se crea una URL pública\npara un bucket que no es público, no podrás descargar el archivo.",[10,119,120],{},"Más tarde, el navegador de un visitante pide ese enlace, y Storage busca el\nbucket solo entre los buckets públicos. Un bucket privado no pasa esa búsqueda,\nigual que uno que no existe, y la respuesta es \"Bucket not found\".",[10,122,123,124,127,128,131],{},"Puedes reconocer esta causa por el propio enlace. Una dirección pública de\narchivo contiene ",[24,125,126],{},"\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002F"," seguido del nombre del bucket. Si\nese bucket no lleva ninguna marca de público en ",[34,129,130],{},"Storage → Buckets",", el enlace\nno iba a abrirse nunca, se escriba como se escriba el nombre.",[10,133,134],{},"Los buckets nuevos empiezan siendo privados, así que el ajuste se está\ncomportando como estaba previsto. Lo que pasó es que el código, tuyo o de tu\nbuilder, se escribió para un bucket público y se apuntó a uno privado.",[136,137],"diagram",{"alt":138,"caption":139,"src":140},"Un almacén de imágenes con una insignia de candado y dos aberturas en su pared izquierda. Una tarjeta con getPublicUrl envía una flecha ámbar a la abertura de arriba, cerrada con una barra y con una cruz encima. Una tarjeta con createSignedUrl envía una flecha turquesa a la abertura de abajo, cuya barra está levantada, y una imagen sale por el otro lado del almacén hacia una persona junto a una marca de verificación.","Un solo bucket privado, dos formas de pedir un archivo. La dirección pública se rechaza en la puerta, y el enlace firmado llega hasta el mismo archivo.","\u002Fblog\u002Fsupabase-bucket-not-found\u002Ftwo-doors-1600x720.png",[39,142,144],{"id":143},"causa-2-un-nombre-que-no-es-exactamente-el-del-bucket","Causa 2: un nombre que no es exactamente el del bucket",[10,146,147,148,151,152,155,156,159,160,162],{},"Storage compara el nombre del bucket carácter por carácter, así que ",[24,149,150],{},"Avatars"," y\n",[24,153,154],{},"avatars"," son dos buckets distintos, igual que ",[24,157,158],{},"avatar"," y ",[24,161,154],{},".",[10,164,165],{},"En el código fuente de Storage la búsqueda es una igualdad simple sobre el id\ndel bucket. Las mayúsculas cuentan, una letra que falta cuenta, y un guion donde\nel bucket tiene un guion bajo cuenta. Cada uno de esos casos vuelve como las\nmismas tres palabras.",[10,167,168],{},"Una app hecha con una herramienta de IA puede llegar aquí sin que nadie haya\nescrito nada mal. El código que sube o muestra un archivo se escribe en un paso,\ny el bucket que nombra se supone que se crea en otro. Si ese segundo paso nunca\nse ejecutó, o se ejecutó con un nombre ligeramente distinto, el código está\npidiendo un bucket que nadie creó.",[10,170,171,172,174],{},"Comprobarlo requiere dos listas. Abre ",[34,173,130],{}," y apunta el nombre\nde cada bucket tal como aparece. Después dile a tu builder, con palabras\nsencillas: haz una lista de cada nombre de bucket de Storage que usa esta app, y\nmuéstrame dónde se usa cada uno. Cualquier nombre de su lista que falte en la\ntuya es el que falla.",[39,176,178],{"id":177},"causa-3-el-bucket-está-en-otro-proyecto","Causa 3: el bucket está en otro proyecto",[10,180,181],{},"Tu app habla con un único proyecto de Supabase, el de su dirección de Supabase,\ny un bucket creado en cualquier otro proyecto simplemente no existe para tu app.",[10,183,184,185,190],{},"Donde esta causa se ve con más claridad es en una subida. En una subida, Storage\nbusca el bucket en todo el proyecto sin aplicar tus reglas de acceso, así que\n\"Bucket not found\" en una subida nunca es un problema de permisos. Cuando el\nbucket existe y tus reglas rechazan el archivo, Storage responde con\n",[186,187,189],"a",{"href":188},"\u002Fblog\u002Fstorage-upload-violates-row-level-security","otro mensaje, que habla de row-level security",".\nAsí que \"Bucket not found\" en una subida significa que ese nombre no existe en el\nproyecto en el que escribe tu app.",[10,192,193],{},"Hay formas muy normales de acabar con dos proyectos: un proyecto de pruebas\njunto al de producción, una copia de la app conectada a un proyecto nuevo, un\nproyecto creado a mano para probar algo. El bucket se crea en el que estuviera\nabierto en el panel en ese momento.",[10,195,196,197,200,201,204,205,208],{},"La comprobación consiste en comparar dos cadenas cortas. La dirección de\nSupabase de tu app tiene la forma ",[24,198,199],{},"https:\u002F\u002F\u003Cref>.supabase.co",", y la parte antes\nde ",[24,202,203],{},".supabase.co"," es la referencia del proyecto. La dirección de tu panel lleva\nesa misma referencia después de ",[24,206,207],{},"\u002Fproject\u002F",". Si las dos no coinciden, estás\nmirando un proyecto mientras tu app habla con otro.",[136,210],{"alt":211,"caption":212,"src":213},"A la izquierda, una ventana de app con una flecha turquesa hacia el proyecto cuya referencia coincide con la suya. Ese proyecto contiene dos buckets apagados y un contorno discontinuo donde debería haber un tercero, marcado con una cruz ámbar. A la derecha, un proyecto aparte con otra referencia contiene el propio bucket, iluminado en turquesa, sin nada que lo una a la app.","El bucket existe. Se creó en el proyecto de la derecha, y cada petición de tu app va al de la izquierda.","\u002Fblog\u002Fsupabase-bucket-not-found\u002Ftwo-projects-1600x700.png",[39,215,217],{"id":216},"deberías-hacer-público-el-bucket-para-arreglarlo","¿Deberías hacer público el bucket para arreglarlo?",[10,219,220],{},"Solo cuando cada archivo del bucket esté pensado para cualquiera que tenga su\ndirección, y solo para la primera causa. Con un nombre equivocado o un proyecto\nequivocado, el interruptor no cambia nada.",[10,222,223],{},"Un bucket público hace una sola cosa, y la documentación de Supabase la describe\nen una línea: cualquiera que tenga la dirección de un archivo puede abrirlo. No\ninterviene ningún inicio de sesión. Los propios ejemplos de Supabase son fotos\nde perfil, contenido multimedia público y contenido de entradas de blog, y los\nlogos o las fotos de producto entran en el mismo grupo.",[10,225,226],{},"Es el ajuste equivocado para facturas, escaneos de documentos de identidad,\nexportaciones o cualquier cosa que pertenezca a una sola persona. El interruptor\nse aplica a todo el bucket y a cada archivo que llegue después, incluidos los de\nuna función que todavía no has construido.",[10,228,229,230,233,234,237],{},"El mismo atajo tiene un gemelo en el lado de las reglas, y es el que nosotros\nmedimos. Una regla sobre ",[24,231,232],{},"storage.objects"," que solo nombra el bucket hace que\nlas descargas funcionen para todo el mundo, y además entrega la lista de nombres\ndel bucket. Hemos escaneado 8.435 apps en producción que nombran un proyecto de\nSupabase. La comprobación de buckets obtuvo respuesta de 4.703 de ellas, y ",[34,235,236],{},"792\nrespondieron a nuestra petición de listado con los nombres de lo que había\ndentro",", sin nadie con la sesión iniciada. Eso es más o menos una de cada seis\nde las apps a las que pudimos preguntar. Cuando un bucket es público y su lista\ntambién está abierta, cada nombre de esa lista es un enlace que funciona.",[39,239,241],{"id":240},"cómo-mostrar-un-archivo-privado-sin-hacerlo-público","Cómo mostrar un archivo privado sin hacerlo público",[10,243,244],{},"Dale a la página un enlace firmado: una dirección que funciona durante los\nsegundos que tú elijas y después deja de funcionar.",[10,246,247,248,251,252,254],{},"La documentación de Supabase nombra dos formas de sacar un archivo de un bucket\nprivado. Una es una descarga que lleva la sesión de la persona que ha iniciado\nsesión. La otra es ",[24,249,250],{},"createSignedUrl",", que genera un enlace \"al que se puede\nacceder durante un tiempo limitado\". Esa segunda ocupa el lugar de\n",[24,253,61],{}," en cualquier página que muestre una imagen.",[10,256,257,258,261,262,264,265,268],{},"Un enlace firmado sigue sometido a tus reglas. Antes de que Storage firme nada,\nsu código fuente comprueba que la persona que lo pide puede leer ese archivo,\nasí que un bucket privado necesita una regla ",[24,259,260],{},"select"," sobre ",[24,263,232],{},"\nque diga quién puede leer qué.\n",[186,266,267],{"href":188},"El error de subida explica cómo se escriben esas reglas",",\nincluido por qué una regla de lectura que solo nombra el bucket abre también su\nlista.",[10,270,271],{},"Para pasárselo a tu builder, con palabras sencillas: para el bucket que da el\nerror \"Bucket not found\", cambia getPublicUrl por createSignedUrl, deja el\nbucket privado y añade una policy de Storage que deje a cada persona leer solo\nlos archivos que debe ver. Después recarga la página que tenía la imagen rota.",[39,273,275],{"id":274},"lo-que-tus-buckets-enseñan-ahora-mismo-a-los-desconocidos","Lo que tus buckets enseñan ahora mismo a los desconocidos",[10,277,278],{},"Dos pantallas del panel te dicen lo que configuraste, y una comprobación desde\nfuera te dice lo que obtiene un desconocido.",[10,280,281,283,284,287,288,290],{},[34,282,130],{}," muestra qué buckets son públicos. Para cada uno, pregúntate\nsi cada archivo que contiene es algo que le enseñarías a un desconocido.\n",[34,285,286],{},"Storage → Policies"," muestra las reglas. Una regla ",[24,289,260],{}," cuya única\ncondición es el nombre del bucket deja que cualquiera lea ese bucket, lista de\narchivos incluida.",[10,292,293,294,162],{},"Nuestro escaneo gratuito le pide a tu proyecto en producción la lista de\narchivos de cada bucket usando solo la clave que ya está en el código de tu app,\ncomo lo haría un desconocido, y te dice qué buckets respondieron con nombres. Lee\nnombres y nunca descarga un archivo. Tarda unos 20 segundos y no necesita\ncuenta: ",[186,295,297],{"href":296},"\u002Fsecurity-scanner","escanea tu app",[39,299,301],{"id":300},"mantener-tus-archivos-donde-los-pusiste","Mantener tus archivos donde los pusiste",[10,303,304],{},"Después del arreglo de hoy todavía pueden moverse dos cosas: alguien cambia un\najuste mientras persigue otro fallo, y se borra un archivo que alguien\nnecesitaba.",[10,306,307],{},[34,308,309,313],{},[186,310,312],{"href":311},"\u002Fwebsite-monitoring","Reeve Monitor"," sigue comprobando desde fuera:",[50,315,316,319,322,329],{},[53,317,318],{},"la comprobación de seguridad completa, repetida según un calendario, incluida la del listado de buckets",[53,320,321],{},"si tu app está en línea",[53,323,324,325,328],{},"un mensaje cuando un resultado ",[34,326,327],{},"cambia",", para que un bucket que se abrió durante la noche no espere a que lo mires",[53,330,331],{},"un informe mensual, en lenguaje claro, de lo que ha visto",[10,333,334],{},[34,335,336,340],{},[186,337,339],{"href":338},"\u002Fsupabase-backups","Reeve Care"," guarda una copia de lo que hay dentro:",[50,342,343,346,349,352,355],{},[53,344,345],{},"una copia cifrada de tu base de datos de Supabase según un calendario, en el almacenamiento propio de Reeve en la UE, fuera de tu cuenta de Supabase",[53,347,348],{},"cada copia verificada antes de contar, contando las filas de cada tabla",[53,350,351],{},"también tus archivos subidos, en cuanto conectas una credencial de Storage",[53,353,354],{},"una restauración con un clic, con una copia de seguridad del estado actual hecha antes",[53,356,357],{},"todo lo que hace Monitor",[39,359,361],{"id":360},"qué-hacer-hoy","Qué hacer hoy",[363,364,365],"key-takeaways",{},[50,366,367,373,376,379,382],{},[53,368,369,370,372],{},"Abre el enlace que falla en una pestaña aparte. Si la dirección contiene ",[24,371,126],{}," y el bucket es privado, es la primera causa.",[53,374,375],{},"Copia el nombre del bucket desde Storage → Buckets y compáralo, mayúsculas incluidas, con el nombre que usa tu app.",[53,377,378],{},"Compara la referencia del proyecto en la dirección de Supabase de tu app con la de la dirección de tu panel.",[53,380,381],{},"Deja un bucket privado salvo que cada archivo que contiene esté pensado para cualquiera que tenga su dirección, y sirve los archivos privados con enlaces firmados.",[53,383,384,385,261,387,389],{},"Lee cada regla ",[24,386,260],{},[24,388,232],{},". Una que solo nombra el bucket entrega también la lista de archivos.",[10,391,392,393,397,398,402],{},"Empieza por la petición que falló, porque la puerta por la que entró te dice\ncuál de las tres causas revisar. La\n",[186,394,396],{"href":395},"\u002Fchecklist","lista de seguridad de 10 minutos"," cubre lo que una app recién\nlanzada suele dejar abierto además de esto, y\n",[186,399,401],{"href":400},"\u002Fblog\u002Fsupabase-storage-bucket-public","lo que expone un bucket público"," es la\nsiguiente lectura si alguno de los tuyos resultó ser público.",{"title":26,"searchDepth":404,"depth":404,"links":405},3,[406,408,409,410,411,412,413,414,415],{"id":41,"depth":407,"text":42},2,{"id":102,"depth":407,"text":103},{"id":143,"depth":407,"text":144},{"id":177,"depth":407,"text":178},{"id":216,"depth":407,"text":217},{"id":240,"depth":407,"text":241},{"id":274,"depth":407,"text":275},{"id":300,"depth":407,"text":301},{"id":360,"depth":407,"text":361},"Fundamentos de seguridad","\u002Fblog\u002Fsupabase-bucket-not-found\u002Fcover-1200x630.png","Una estantería de buckets, uno cerrado con un candado. Delante, una etiqueta ámbar cuya línea discontinua se detiene en una barra antes de él.","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.",false,"md",[423,426,429,432,435],{"q":424,"a":425},"¿Por qué Supabase dice que mi bucket no existe si lo estoy viendo?","Porque Storage busca un bucket de forma distinta según la petición. Una dirección pública de archivo, la que genera getPublicUrl, solo se busca entre los buckets públicos, así que un bucket privado que ves en el panel aparece ahí como no encontrado. Si el error vino de una subida, el nombre de tu código no coincide exactamente con ningún bucket del proyecto al que está conectada tu app.",{"q":427,"a":428},"¿El nombre de un bucket de Supabase distingue mayúsculas y minúsculas?","Sí. Storage compara el nombre carácter por carácter, así que Avatars y avatars son dos buckets distintos, igual que avatar y avatars. Copia el nombre desde Storage → Buckets en tu panel y compáralo con el nombre que usa tu app.",{"q":430,"a":431},"¿Debo hacer público mi bucket para arreglar \"Bucket not found\"?","Solo si cada archivo que contiene está pensado para cualquiera que tenga su dirección, como fotos de perfil o fotos de producto. Público significa que cualquiera con la dirección de un archivo puede abrirlo sin iniciar sesión. Eso solo arregla el error cuando se creó un enlace público para un bucket privado; un nombre equivocado o un proyecto equivocado sigue roto igual. Para archivos que pertenecen a una sola persona, deja el bucket privado y usa un enlace firmado.",{"q":433,"a":434},"¿Cómo muestro un archivo de un bucket privado?","Con un enlace firmado. createSignedUrl genera una dirección que funciona durante los segundos que tú elijas y después deja de funcionar, y ocupa el lugar de getPublicUrl en cualquier página que muestre el archivo. Quien pide el enlace tiene que poder leer el archivo, así que el bucket necesita una regla select sobre storage.objects que diga quién puede leer qué.",{"q":436,"a":437},"¿Por qué el error dice 404 si la petición falló con 400?","Supabase Storage envía este error con el estado HTTP 400 y pone su propio estado, 404, dentro del cuerpo como statusCode. En supabase-js eso llega como error.status 400 y error.statusCode \"404\", y por eso el código escrito para atrapar un 404 deja pasar este error sin verlo.","\u002Fblog\u002Fsupabase-bucket-not-found\u002Fcard-800x500.png",[440,441,442,443,444,445,446],"supabase bucket not found","supabase storage bucket not found","bucket not found getpublicurl","supabase url pública bucket not found","supabase subida bucket not found","supabase storage 404","supabase url firmada bucket privado",{},true,"\u002Fblog\u002Fsupabase-bucket-not-found","2026-10-17",{"title":5,"description":419},"blog\u002Fsupabase-bucket-not-found",[454,455,456,457],"Supabase \"Bucket not found\" significa que Storage buscó un bucket con ese nombre exacto, en el proyecto al que llegó tu petición, y no encontró ninguno que estuviera dispuesto a servir a esa petición. El bucket puede seguir ahí, en tu panel.","Un enlace creado con getPublicUrl para un bucket privado da este error al abrirlo, porque Storage sirve esos enlaces solo desde buckets públicos.","En una subida significa que el nombre no existe en ese proyecto. Revisa la ortografía y las mayúsculas, y después a qué proyecto apunta tu app.","Hacer público el bucket acaba con el mensaje y deja que cualquiera con la dirección de un archivo lo abra. Para archivos que pertenecen a una sola persona, usa un enlace firmado.","XKd5hrCz352fgaW4RfanPPYFSL6GZVeBiBpe10wuaqA",[460,466,472,478,484,490,496,502,508,514,520,527,533,539,545,551,557,563,569,575,581,587,593,599,600,606,612,618,624,630,635,641,647,653,659,665,671,677,683,689,695,701,707,713,719,725,730,736,742,748,754,760,766,772,778,784,790,796,802,808,814,820,826,832,838,844,850,856,862,868,874,880,886,892,898,904,910,916,922,928,933,939,945,951,956,962,968,974,979,985],{"path":461,"title":462,"description":463,"published":464,"category":416,"image":465,"draft":420},"\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":467,"title":468,"description":469,"published":470,"category":416,"image":471,"draft":420},"\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":473,"title":474,"description":475,"published":476,"category":416,"image":477,"draft":420},"\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":479,"title":480,"description":481,"published":482,"category":416,"image":483,"draft":420},"\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":485,"title":486,"description":487,"published":488,"category":416,"image":489,"draft":420},"\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":491,"title":492,"description":493,"published":494,"category":416,"image":495,"draft":420},"\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":497,"title":498,"description":499,"published":500,"category":416,"image":501,"draft":420},"\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":503,"title":504,"description":505,"published":506,"category":416,"image":507,"draft":420},"\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":509,"title":510,"description":511,"published":512,"category":416,"image":513,"draft":420},"\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":515,"title":516,"description":517,"published":518,"category":416,"image":519,"draft":420},"\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":521,"title":522,"description":523,"published":524,"category":525,"image":526,"draft":420},"\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":528,"title":529,"description":530,"published":531,"category":416,"image":532,"draft":420},"\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":534,"title":535,"description":536,"published":537,"category":416,"image":538,"draft":420},"\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":540,"title":541,"description":542,"published":543,"category":416,"image":544,"draft":420},"\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":546,"title":547,"description":548,"published":549,"category":416,"image":550,"draft":420},"\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":552,"title":553,"description":554,"published":555,"category":416,"image":556,"draft":420},"\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":558,"title":559,"description":560,"published":561,"category":416,"image":562,"draft":420},"\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":564,"title":565,"description":566,"published":567,"category":416,"image":568,"draft":420},"\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":570,"title":571,"description":572,"published":573,"category":416,"image":574,"draft":420},"\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":576,"title":577,"description":578,"published":579,"category":416,"image":580,"draft":420},"\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":582,"title":583,"description":584,"published":585,"category":416,"image":586,"draft":420},"\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":588,"title":589,"description":590,"published":591,"category":416,"image":592,"draft":420},"\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":594,"title":595,"description":596,"published":597,"category":416,"image":598,"draft":420},"\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":449,"title":5,"description":419,"published":450,"category":416,"image":438,"draft":420},{"path":601,"title":602,"description":603,"published":604,"category":416,"image":605,"draft":420},"\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":607,"title":608,"description":609,"published":610,"category":416,"image":611,"draft":420},"\u002Fblog\u002Fsupabase-single-row-error","Supabase \"multiple (or no) rows returned\" casi siempre es ninguna","Supabase devuelve PGRST116, \"JSON object requested, multiple (or no) rows returned\", cuando tu consulta no encontró nada. Una fila oculta parece ausente.","2026-10-15","\u002Fblog\u002Fsupabase-single-row-error\u002Fcard-800x500.png",{"path":613,"title":614,"description":615,"published":616,"category":416,"image":617,"draft":420},"\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":619,"title":620,"description":621,"published":622,"category":416,"image":623,"draft":420},"\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":625,"title":626,"description":627,"published":628,"category":416,"image":629,"draft":420},"\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":188,"title":631,"description":632,"published":633,"category":416,"image":634,"draft":420},"\"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":636,"title":637,"description":638,"published":639,"category":416,"image":640,"draft":420},"\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":642,"title":643,"description":644,"published":645,"category":416,"image":646,"draft":420},"\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":648,"title":649,"description":650,"published":651,"category":416,"image":652,"draft":420},"\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":654,"title":655,"description":656,"published":657,"category":416,"image":658,"draft":420},"\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":660,"title":661,"description":662,"published":663,"category":416,"image":664,"draft":420},"\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":666,"title":667,"description":668,"published":669,"category":416,"image":670,"draft":420},"\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":672,"title":673,"description":674,"published":675,"category":416,"image":676,"draft":420},"\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":678,"title":679,"description":680,"published":681,"category":416,"image":682,"draft":420},"\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":684,"title":685,"description":686,"published":687,"category":416,"image":688,"draft":420},"\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":690,"title":691,"description":692,"published":693,"category":416,"image":694,"draft":420},"\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":696,"title":697,"description":698,"published":699,"category":416,"image":700,"draft":420},"\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":702,"title":703,"description":704,"published":705,"category":416,"image":706,"draft":420},"\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":708,"title":709,"description":710,"published":711,"category":525,"image":712,"draft":420},"\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":714,"title":715,"description":716,"published":717,"category":525,"image":718,"draft":420},"\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":720,"title":721,"description":722,"published":723,"category":525,"image":724,"draft":420},"\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":726,"title":727,"description":728,"published":723,"category":416,"image":729,"draft":420},"\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":731,"title":732,"description":733,"published":734,"category":416,"image":735,"draft":420},"\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":737,"title":738,"description":739,"published":740,"category":416,"image":741,"draft":420},"\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":743,"title":744,"description":745,"published":746,"category":525,"image":747,"draft":420},"\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":749,"title":750,"description":751,"published":752,"category":416,"image":753,"draft":420},"\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":755,"title":756,"description":757,"published":758,"category":416,"image":759,"draft":420},"\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":761,"title":762,"description":763,"published":764,"category":416,"image":765,"draft":420},"\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":767,"title":768,"description":769,"published":770,"category":416,"image":771,"draft":420},"\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":773,"title":774,"description":775,"published":776,"category":416,"image":777,"draft":420},"\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":779,"title":780,"description":781,"published":782,"category":416,"image":783,"draft":420},"\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":785,"title":786,"description":787,"published":788,"category":416,"image":789,"draft":420},"\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":791,"title":792,"description":793,"published":794,"category":416,"image":795,"draft":420},"\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":797,"title":798,"description":799,"published":800,"category":525,"image":801,"draft":420},"\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":803,"title":804,"description":805,"published":806,"category":525,"image":807,"draft":420},"\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":809,"title":810,"description":811,"published":812,"category":525,"image":813,"draft":420},"\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":815,"title":816,"description":817,"published":818,"category":416,"image":819,"draft":420},"\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":821,"title":822,"description":823,"published":824,"category":416,"image":825,"draft":420},"\u002Fblog\u002Fenable-rls-on-every-supabase-table","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":827,"title":828,"description":829,"published":830,"category":416,"image":831,"draft":420},"\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":833,"title":834,"description":835,"published":836,"category":416,"image":837,"draft":420},"\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":839,"title":840,"description":841,"published":842,"category":416,"image":843,"draft":420},"\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":845,"title":846,"description":847,"published":848,"category":416,"image":849,"draft":420},"\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":851,"title":852,"description":853,"published":854,"category":416,"image":855,"draft":420},"\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":857,"title":858,"description":859,"published":860,"category":416,"image":861,"draft":420},"\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":863,"title":864,"description":865,"published":866,"category":416,"image":867,"draft":420},"\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":869,"title":870,"description":871,"published":872,"category":416,"image":873,"draft":420},"\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":875,"title":876,"description":877,"published":878,"category":525,"image":879,"draft":420},"\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":881,"title":882,"description":883,"published":884,"category":416,"image":885,"draft":420},"\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":887,"title":888,"description":889,"published":890,"category":525,"image":891,"draft":420},"\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":893,"title":894,"description":895,"published":896,"category":416,"image":897,"draft":420},"\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":899,"title":900,"description":901,"published":902,"category":416,"image":903,"draft":420},"\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":905,"title":906,"description":907,"published":908,"category":416,"image":909,"draft":420},"\u002Fblog\u002Fnew-row-violates-row-level-security-policy","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":911,"title":912,"description":913,"published":914,"category":416,"image":915,"draft":420},"\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":917,"title":918,"description":919,"published":920,"category":525,"image":921,"draft":420},"\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":923,"title":924,"description":925,"published":926,"category":525,"image":927,"draft":420},"\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":400,"title":929,"description":930,"published":931,"category":416,"image":932,"draft":420},"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":934,"title":935,"description":936,"published":937,"category":416,"image":938,"draft":420},"\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":940,"title":941,"description":942,"published":943,"category":525,"image":944,"draft":420},"\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":946,"title":947,"description":948,"published":949,"category":416,"image":950,"draft":420},"\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":952,"title":953,"description":954,"published":949,"category":416,"image":955,"draft":420},"\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":957,"title":958,"description":959,"published":960,"category":416,"image":961,"draft":420},"\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":963,"title":964,"description":965,"published":966,"category":525,"image":967,"draft":420},"\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":969,"title":970,"description":971,"published":972,"category":416,"image":973,"draft":420},"\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":975,"title":976,"description":977,"published":972,"category":525,"image":978,"draft":420},"\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":980,"title":981,"description":982,"published":983,"category":525,"image":984,"draft":420},"\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":986,"title":987,"description":988,"published":983,"category":416,"image":989,"draft":420},"\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",1794213645216]