1 puntos por GN⁺ 2 시간 전 | 1 comentarios | Compartir por WhatsApp
  • La base de datos detectó hoy un UUID v4 duplicado, y el valor existente era exactamente igual a b6133fd6-70fe-4fe3-bed6-8ca8fc9386cd de un registro agregado en 2025
  • El paquete en uso es uuid de npm, y dice que lo genera con import { v4 as uuidv4 } from "uuid"; y luego const document_id = uuidv4(); para insertarlo en la base de datos
  • La base de datos solo tiene alrededor de 15,000 registros, así que parece estadísticamente imposible, y pregunta si alguien más ha pasado por lo mismo

1 comentarios

 
GN⁺ 2 시간 전
Opiniones de Hacker News
  • jandrewrogers: Esto es sorprendentemente común. La seguridad de UUIDv4 depende de la suposición de que existe una fuente de entropía de alta calidad, y esa suposición se rompe con facilidad por fallas de hardware, bugs de software bastante comunes o porque los desarrolladores no entienden bien la entropía.
    Detectar que una fuente de entropía está rota es bastante costoso, así que casi nadie lo hace, y al final uno se entera solo después de que ocurre una colisión. Por eso, en muchos sistemas de alta confiabilidad y alta garantía, UUIDv4 está explícitamente prohibido.

    • LocalH: Por eso CloudFlare hizo algo como la pared de lámparas de lava. No tanto porque eso por sí solo sea una fuente enorme de entropía, sino porque hace visible el concepto de generación aleatoria y de entropía incluso para gente que no lo entiende bien.
      Cuantas más fuentes de entropía haya, mejor, y una buena parte de ellas debería ser no determinista. Incluso en juegos pequeños, si mezclas en la semilla inicial valores como las coordenadas del mouse, el intervalo entre pulsaciones de botones o la cantidad de frames antes de presionar iniciar, se vuelve mucho más difícil de predecir aunque internamente uses un generador seudoaleatorio. Si CloudFlare usara menos de 100 fuentes de entropía, me decepcionaría.
    • Groxx: He visto duplicados plausibles por hardware defectuoso. Y en algunas bibliotecas de UUID también era muy común un patrón de duplicados con la parte final rellena de ceros.
      Eso pasa si no verificas valores de retorno del estilo “pediste N bytes pero solo se devolvieron 3, así que hay que volver a pedir los N-3 restantes”, como ocurría antes en el ecosistema de Go. Como en la mayoría del hardware o sistemas operativos casi nunca falla, la gente no lo revisa, y un día aparece en producción convertido en decenas de miles de colisiones.
    • thecloud: Me da curiosidad qué alternativas usan en sistemas de alta confiabilidad en lugar de UUIDv4.
  • throwaway_19sz: Suena a historia increíblemente absurda, pero es real. Hace 10 años, un amigo entró como CTO a una startup de alto crecimiento; la empresa tenía como 200 desarrolladores y en su primera semana descubrió que existía un microservicio dedicado exclusivamente a generar UUID.
    Había 3 ingenieros asignados a un solo endpoint, e incluso una persona de base de datos. Si algún equipo necesitaba un UUID nuevo y “seguro”, tenía que llamar a ese servicio; el servicio generaba el UUID, revisaba en su propia base si ya existía uno igual emitido antes, y si no, lo insertaba y lo devolvía. No sé si era por tranquilidad mental, pero ese equipo hasta tenía su propio tablero kanban y sus sprints.

    • Aurornis: Al principio trabajé en startups con recursos limitados, así que cada vez que hacíamos algo o contratábamos a alguien lo pensábamos con mucho cuidado. En esa época, esta historia me habría parecido ficción.
      Después entré a otra startup donde cada vez que a alguien se le ocurría una nueva preocupación, nacían un nuevo microservicio y un nuevo equipo. Uno de los objetivos trimestrales era explícitamente aumentar el tamaño del equipo de ingeniería, y los equipos de 3 o 4 personas se inventaban trabajo dentro de sus propios sprints y reuniones de planeación. Propuse mover gente de proyectos estables a tareas urgentes, pero me lo bloquearon porque chocaba con un KPI que exigía aumentar el número de ingenieros hasta cierta cifra.
    • wongarsu: Algún día va a aparecer alguien que lo optimice con un contador incremental global de 128 bits para toda la empresa. Sin consultar una base de datos que no deja de crecer, tomas el contador actual, le sumas 1 y lo repartes: O(1) y rápido.
      Para alta disponibilidad y despliegue global, también se puede shardear asignando rangos de ID dedicados a cada instancia. Reservas algunos bits altos para el ID del datacenter y unos cuantos bits para la instancia generadora dentro de ese datacenter. Espera, esto me suena conocido… Me pregunto si Twitter todavía usa este enfoque o si al final lo cambiaron.
    • roryirvine: Vi algo parecido en las profundidades de una gran empresa tecnológica de Silicon Valley. Solo que era más complejo porque la lista maestra de UUID en uso estaba en un servicio externo de CMDB operado por otro departamento.
      Cada día recibían un dump de la base de datos para validarlo al generar IDs “temporales”, y recién quedaban “confirmados” después de enviarlos correctamente al CMDB. También había guardrails para que los IDs temporales no terminaran usándose en producción, y existía un proceso para reciclar IDs confirmados que no se habían usado. La última vez que supe, llevaban 18 meses en un proyecto de 6 meses para mover la caché local de la base de datos a Zookeeper.
  • CodesInChaos: Normalmente esto pasa por un generador seudoaleatorio con mala semilla. Importa si el UUID se generó en el backend o en el frontend.
    El frontend es inherentemente difícil de confiar por muchas razones, incluidas colisiones intencionales, así que hay que manejar colisiones. El backend sí puede hacerse confiable. Antes esto pasaba con VM, pero hoy en día ya debería estar resuelto, aunque todavía puede ocurrir si un proceso muy aislado en sandbox usa una ruta alternativa de aleatoriedad no segura. También un fork de proceso o de VM puede producir colisiones al copiar el estado.

    • danpalmer: Recuerdo haber oído que una empresa de analítica llamada Segment estaba apostando todo su producto a UUID generados en el navegador. Hubo colisiones de UUID en el navegador por todas partes y parecía que el producto, en esencia, no podía generar datos útiles. Espero que ya lo hayan arreglado.
  • kst: Esto me recordó un pasaje de “Pro Git”. <https://git-scm.com/book/en/v2>
    El ejemplo decía que, incluso si los 6,500 millones de personas del planeta produjeran cada segundo una cantidad de código equivalente a toda la historia del kernel de Linux y la hicieran push a un único repositorio gigante de Git, tardarías aproximadamente 2 años en llegar a una probabilidad del 50% de colisión de objetos SHA-1. Así que me gustaba la frase de que una colisión natural de SHA-1 es menos probable que que todos los miembros de tu equipo mueran la misma noche en ataques de lobos no relacionados entre sí. SHA-1 no es un número aleatorio y tiene 160 bits, así que es distinto de UUIDv4, pero me encanta la comparación de ataques de lobos no relacionados.

    • mega_dean: Esto me recordó la página que explica qué tan grande es el número de permutaciones al barajar una baraja: https://czep.net/weblog/52cards.html
      Es esa analogía de dar una vuelta a la Tierra cada mil millones de años caminando por el ecuador, quitar una gota de agua del Pacífico en cada vuelta, y cuando el océano se vacíe poner una hoja de papel; incluso repitiendo eso hasta llegar al Sol, los tres primeros dígitos del temporizador de 52! segundos no cambiarían.
    • swiftcoder: En cambio, los ataques de diccionario sí son bastante reales, y pueden ser bastante molestos, como pueden atestiguarlo quienes hicieron commit sin pensar de ese archivo de casos de prueba a Git.
    • TacticalCoder: ¿No estaba el equipo de Git trabajando duro para ofrecer opcionalmente otro hash además de SHA-1, como SHA256?
  • e12e: Hay una discusión relacionada aquí: https://github.com/uuidjs/uuid/issues/546
    Por ejemplo, mencionan que al probar crypto.getRandomValues() con googlebot, este resultó ser determinista.

    • D2OQZG8l5BI1S06: Tiene sentido. Aun así, no entiendo por qué alguien generaría UUID en el navegador. Parece ir en contra del propósito.
  • adyavanapalli: Lo que están describiendo es tan raro que, en este mismo instante, sería más probable que la Tierra entera fuera destruida por un asteroide.

    • thomasmg: No es tan raro. Hice las cuentas y resultó ser más raro que ser alcanzado por un meteorito, y llegué a agregar eso junto con el problema del cumpleaños al artículo de Wikipedia sobre UUID. Hace unos años lo borraron y lo reemplazaron.
      Tengo entendido que sí hubo una mujer que fue alcanzada por un meteorito y sobrevivió con una lesión en la pierna. Si hubo una colisión de UUID, es abrumadoramente más probable que haya sido por un bug de software o una anomalía en la computadora, aunque también podría ser radiación cósmica. Los rayos cósmicos afectan memoria o CPU más seguido de lo que uno cree.
    • delichon: Más o menos la misma probabilidad de que un asteroide escriba los puntos suspensivos y luego haga clic en agregar comentario.
    • spindump8930: Como ya dijeron otros, si la semilla está mal puesta, esto es bastante común. La analogía sería algo así como la probabilidad de que la Tierra reciba impactos estando rodeada por un cinturón de asteroides denso, como en la ciencia ficción.
  • juancn: ¿No será un problema raro de inicialización del generador aleatorio o falta de entropía? Si no lo personalizaron, entonces usan crypto.getRandomValues(rnds8), y getRandomValues no especifica una cantidad mínima de entropía.

    • Hizonner: Casi seguro que el generador aleatorio estaba gravemente roto, probablemente por un problema en cómo manejaba la semilla. Es muy posible que también esté rompiendo la criptografía.
  • Geee: Según la interpretación de muchos mundos de la mecánica cuántica, debe existir alguna rama del universo donde todos los UUID sean iguales. Me pregunto qué pensarán las personas de ese mundo.

    • suprjami: Seguramente, después de generar “ese UUID”, le pondrán un número incremental al final para volverlo único. Problema resuelto.
    • BobaFloutist: No solo eso: debe haber muchísimos más universos casi idénticos salvo por un solo UUID. Solo que en esos no llegaron a usar ese último. O universos donde solo los dos primeros UUID son únicos y luego todos los demás son uno de esos dos.
    • nyantaro1: Por eso no me gusta mucho el enfoque estilo Everett.
  • mittermayr: Estoy totalmente de acuerdo en que no tiene sentido. Aun así, si tuviera que adivinar, la diferencia sería que antes generaban UUIDv4 en el teléfono del usuario y los enviaban a la base de datos, mientras que el UUID que colisionó esta mañana se generó en un servidor Ubuntu.
    No sé exactamente cómo se genera UUIDv4 ni si las características de la máquina generadora entran en el algoritmo, pero el único cambio que se me ocurre es que antes se generaban en el dispositivo y desde hace unos meses se generan en el servidor.

    • AntiUSAbah: ¿Le hacían generar el UUID al usuario? Sinceramente, me parece mucho más probable que haya habido una implementación rara que una colisión real de UUID. Me da curiosidad cómo mostró esa colisión la base de datos.
    • wongarsu: Si ambos UUID se generaron en el dispositivo, puedo entender mejor la posibilidad de colisión. Ha habido casos donde en dispositivos baratos la semilla del generador aleatorio no quedaba bien establecida y esos valores “aleatorios” terminaban chocando, y sería peor si la biblioteca usara un generador barato en lugar de uno criptográfico correcto.
      Pero en el servidor, especialmente en 2026, eso no debería pasar. Antes hubo problemas con semillas de aleatoriedad en VM, pero ahora debería ser menos común. Incluso si uno de los UUID se generó mal, la probabilidad de que un UUID realmente aleatorio colisione con ese sigue siendo bajísima, así que tendrían que estar mal ambos generadores.
    • stubish: Una colisión UUIDv4 es estadísticamente extremadamente improbable. Lo más plausible es que ambos sistemas hayan usado la misma semilla. Si la semilla tiene apenas unos pocos bytes, la probabilidad de colisión puede subir de una entre miles de millones a una entre millones.
  • dweez: Es hora de volver a ver este artículo divertido: https://jasonfantl.com/posts/Universal-Unique-IDs/
    Si convirtiéramos todo el universo en una computadora gigantesca para generar UUID hasta la muerte térmica, ¿cuántos bits necesitaría el espacio de IDs?

    • CodeWriter23: Si van a llegar tan lejos, entonces esto es obligatorio: https://www.decisionproblem.com/paperclips/
    • ipaddr: El ejemplo de “¿te preocupa que todas las personas del planeta sean alcanzadas por meteoritos ahora mismo?” puede no ser tan bueno. Un solo meteorito podría acabar con el mundo y, si le das suficiente tiempo, esa posibilidad aumenta bastante.
  • beejiu: Me pregunto si el UUID se genera del lado del cliente o del servidor. Si es del lado del cliente, podría deberse a bots de rastreo. Por ejemplo, Googlebot ejecuta JavaScript con una “aleatoriedad” determinista.

    • adzm: En el incidente anterior de ese paquete, la conclusión también fue la falta de aleatoriedad de Googlebot: https://github.com/uuidjs/uuid/issues/546
    • AgentME: Casi seguro que en este caso fue eso, o que estaban usando una versión vieja de un paquete que no lograba usar correctamente el generador aleatorio del sistema, o que cargaron un polyfill viejo y roto que reimplementaba la API crypto de JS, o una configuración extraña de hosting donde varias máquinas reanudaban el mismo snapshot de VM y por eso se duplicaba el estado aleatorio.
      Explicaciones de este tipo son varios órdenes de magnitud más plausibles que una colisión realmente aleatoria.
  • merlindru: Probablemente es un problema de semilla. Si puedes demostrar que no lo es, tal vez te vuelvas un poco famoso.

  • erlkonig: Siempre le he dicho a mi equipo que, con suficiente volumen de datos, los valores aleatorios pueden colisionar tarde o temprano, y ahí es cuando ves qué tan robusto es tu software.
    Aun así, hay muchos desarrolladores con experiencia, líderes de equipo y CIO que creen que eso es imposible y no escriben nada de código para manejar ese caso. Entonces un mal generador aleatorio puede romper el sistema mucho antes de lo esperado, e incluso provocar corrupción simultánea sin detección ni regeneración. Me suena a la misma clase de gente que no verifica si malloc() tuvo éxito. A veces les pregunto: “si de verdad es imposible, ¿no estaremos usando demasiados bits?”.

  • leni536: No fue una coincidencia; hay un bug en alguna parte. Viendo por encima, el paquete parece llamar a crypto.randomUUID() del runtime de JS, y eso siempre debería estar correctamente inicializado.
    La posibilidad de un bug en el runtime parece bajísima, pero quién sabe. Me da curiosidad qué runtime de JS usan.

  • jbverschoor: La causa más plausible es que el paquete de generación aleatoria del que depende uuid haya sido comprometido recientemente para volver predecibles los números “aleatorios”. Como resultado, muchos proyectos relacionados con criptografía, SSL o monedas podrían haber quedado en riesgo por un ataque a la cadena de suministro.

    • jbverschoor: Hace 3 semanas cambiaron uuid/src/rng.ts y el arreglo aleatorio pasó a ser const. Eso hace que todas las llamadas compartan el mismo arreglo aleatorio.
      Luego las llamadas posteriores van actualizando el código aleatorio anterior, así que si generaste algo importante, buena suerte. Antes el código hacía una copia nueva con slice(). Puede haber sido un cambio accidental, pero no entiendo cómo pasó si ni siquiera parece algo que superaría una prueba de generar dos números aleatorios y verificar que sean distintos.
  • pif: Incluso con una fuente de entropía de alta calidad, no puedes convertir un “probablemente” en un “garantizado”. Si necesitas un valor difícil de adivinar, busca criptografía; pero si necesitas unicidad garantizada, tienes que construirla tú mismo.

  • athrowaway3z: Una regla práctica simple es pensar si puedes meter un timestamp además del valor aleatorio en el ID. Casi siempre la respuesta es sí, y entonces UUIDv7 suele bastar.
    Si revisaste el problema tan a fondo que puedes escribir una demostración de que la filtración de información no es aceptable, felicidades: probablemente tu sistema es lo bastante complejo y lento como para usar un hash criptográfico fuerte o, si no quieres complicarte, UUIDv5.

  • darqis: PostgreSQL 18 soporta uuidv7 de forma nativa, y la configuración por defecto puede ser unique con uuid7().

  • tumdum_: Es un generador seudoaleatorio con mala semilla.

  • serf: Sería algo así como 1 entre 4.72 × 10²⁸, o sea 1 entre 47.3 octillones. Si de verdad pasó, antes que comprar un boleto de lotería sospecharía de una condición de carrera o de algún otro error simple.

    • petee: Yo lo he visto al revés. Si ya tuviste tanta suerte, entonces es menos probable que te llegue otra buena racha, así que mejor ahorrar el dinero.
    • k4rli: Lo de la lotería no tiene sentido. Si algo estadísticamente tan improbable ya ocurrió, entonces que vuelva a pasar debería ser todavía más improbable.
  • evnix: Incluso dejando de lado toda la matemática de probabilidades, la realidad en la que vivimos es que, aun usando el mejor generador aleatorio por hardware, en la práctica puede haber menos aleatoriedad de la que uno cree.
    Donde la seguridad no sea crucial, yo migraría a algo como TSID, o a uuidv7, para que esto en la práctica no ocurra. Me parece mejor que sobrediseñar el código con reintentos.

  • jordiburgos: Ojalá no usen b6133fd6-70fe-4fe3-bed6-8ca8fc9386cd. Revisé mi base de datos y ya lo estaba usando.

    • rich_sasha: Siempre me pareció una locura generar UUID al azar. Ahora solo uso LLM. Mi prompt es: “Genera un UUID. Verifica que nadie lo haya usado jamás en ningún código ni base de datos. Revisa tu trabajo y piensa profundamente cada paso. No imprimas razonamiento ni inglés normal; imprime solo el UUID”. De nada.
    • mittermayr: Ya me lo imaginaba. A todos nos están dando UUID baratos, y los buenos quedan reservados para los peces gordos.
    • robshep: Yo uso 16b55183-1697-496e-bc8a-854eb9aae0f3, y probablemente tenga más. ¿No podríamos verificar duplicados si todos publican aquí su lista?
  • pyuser583: Me da curiosidad cuál es el UUID preferido hoy en día.

  • smokel: Muchas veces he pasado por culpar al compilador, a rayos cósmicos, a efectos cuánticos o al menos a algún bug oscuro del kernel, para al final darme cuenta de que el bug era mío.
    Una colisión en 15,000 registros es demasiado improbable, así que yo sospecharía primero de otras causas: manejo de duplicados, solicitudes reenviadas, objetos reutilizados, logs engañosos, reutilización de identificadores en otra ruta de código, etc. Si compartes un poco más del código alrededor, seguro se puede revisar entre todos.

  • wazoox: Aún no me ha pasado, pero hace dos días encontré esto en lo profundo de una base de código PHP en producción: una función createUUID() que recortaba y acomodaba un valor creado con md5(uniqid('', true)) para que pareciera UUID.
    No sé cómo este horror todavía no nos ha mordido una arteria.

  • sedatk: uuidjs/uuid tiene una advertencia de que puede generar UUID duplicados en clientes con generadores aleatorios deterministas como Googlebot.
    Dice que esto puede ser un problema para aplicaciones que esperan que los UUID generados del lado del cliente siempre sean únicos, así que recomiendan verificar duplicados y fallar con elegancia, o deshabilitar operaciones de escritura para clientes tipo Googlebot: https://github.com/uuidjs/uuid/commit/91805f665c38b691ac2cbd...

  • xyzzy123: Una vez una prueba de carga larga falló por UUID duplicados en un sistema distribuido basado en Linux.
    Después de investigar mucho, resultó ser un bug del kernel, concretamente una condición de carrera. En sistemas multiprocesador, si dos procesos leen /dev/random al mismo tiempo, en casos muy raros, del orden de una vez entre un millón, podían recibir los mismos bytes. Yo empezaría revisando la inicialización del generador aleatorio.

  • baq: Parece que la VM en ejecución virtualizó toda la entropía hasta hacerla desaparecer.

  • glaslong: Hay que comprar unas lámparas de lava.

  • 0xfffafaCrash: Me da curiosidad si el UUID se generó en el frontend o en el backend. Si fue en el frontend, antes que un problema de entropía apostaría a que se manipuló el código del cliente o la solicitud para inyectar un UUID ya conocido.

  • latentframe: Una de las frases más peligrosas en ingeniería es estadísticamente imposible. A suficiente escala, los casos extremos dejan de ser teoría y se vuelven eventos operativos.

  • 8organicbits: El año pasado escribí sobre una colisión real, incluyendo la biblioteca implicada: https://alexsci.com/blog/uuid-oops/
    Para que un UUID tenga resistencia a colisiones, hay muchas restricciones que deben respetarse con rigor, y aquí parece muy probable que el problema esté en el generador aleatorio.

  • nu11ptr: Al final es un problema de fuente de entropía. Por eso yo siempre genero e inserto dentro de un loop. Si hay colisión, se puede manejar con elegancia.

  • sbuttgereit: No es “técnicamente imposible”. Es muy técnicamente posible. Con buena aleatoriedad es extremadamente, extremadamente raro, pero no hay nada en UUIDv4 que impida técnicamente producir un valor duplicado.

  • beardyw: Puede que sea una pregunta tonta, pero ¿no se podría agregar la fecha, aunque sea en segundos hexadecimales? Siento que con apenas unos bytes extra, algo que hoy está bien quedaría garantizado también para el futuro.

    • flohofwoe: Solo hay que usar otra variante de UUID que incluya datos de timestamp. Por ejemplo v1 o v7, y también hay variantes que incluyen la dirección MAC.
    • itsyonas: Simplemente usa uuidv7.
    • mittermayr: Sí, cualquier forma de datos seudoaleatorios adicionales habría ayudado a evitar algo así. Aunque esa también era la idea de UUIDv4. Yo pensaba que ya incluía mucha aleatoriedad y tiempo.
  • mdavid626: También puede haber otras explicaciones. Por ejemplo, que alguien haya manipulado manualmente una solicitud o la base de datos.

  • radial_symmetry: A mí me pasó una vez algo así y pensé que me estaba volviendo loco, pero leer estos comentarios me tranquiliza.

  • NKosmatos: No es “técnicamente imposible”. No es imposible; es simplemente extremadamente, extremadamente improbable. Creo que deberías comprar un boleto de lotería.
    Cada vez que uso la palabra “improbable”, me acuerdo de https://hitchhikers.fandom.com/wiki/Infinite_Improbability_D...

    • sebazzz: En realidad no deberías comprarlo. Que ocurran tanto esa colisión como ganar la lotería sería todavía más raro.
    • rithdmc: Inimaginable.
  • sudb: Por primera vez siento que elegir CUID2 en uno de mis proyectos sí fue una buena idea de verdad: https://github.com/paralleldrive/cuid2