SQLite arrastró un error de corrupción durante 16 años. Por qué el suyo probablemente está bien y qué revisar de todos modos.

Esta semana Tailscale publicó un postmortem que todo equipo que ejecute SQLite debería leer. Durante seis meses, comenzando el pasado agosto, su plano de control seguía corrompiendo bases de datos. Diecinueve incidentes separados, sin un desencadenante obvio, sin ningún cambio reciente en el código que lo explicara. La causa resultó ser una condición de carrera que había estado en SQLite desde la versión 3.7.0, publicada en julio de 2010. Estuvo oculta allí durante aproximadamente dieciséis años.

El equipo de SQLite lo llama el error de reinicio de WAL. Solo afecta a bases de datos que se ejecutan en modo WAL (registro de escritura anticipada) cuando dos o más conexiones tienen el mismo archivo abierto en hilos o procesos separados, e intentan escribir o hacer un checkpoint al mismo tiempo. Cuando el momento se alinea, un checkpoint puede dejar una marca en el índice WAL afirmando que parte del registro ya se copió al archivo principal de la base de datos cuando no fue así. Un checkpoint posterior omite esos datos y el archivo se corrompe. Se corrigió en SQLite 3.51.3 el 13 de marzo de 2026, con retroportados a 3.44.6 y 3.50.7.

Esta es la parte que vale la pena asimilar. Los desarrolladores de SQLite no pudieron reproducir este error de forma intencionada. Tuvieron que parchear su propio código fuente para activar una devolución de llamada exactamente en el momento incorrecto durante un checkpoint. Sus propios datos de telemetría sitúan la tasa de impacto real al nivel o por debajo de la tasa de fallos de SSD y de inversión de bits por rayos cósmicos. Así que si usted ejecuta SQLite en una configuración normal, casi con certeza nunca fue afectado, y probablemente sigue sin serlo. Tailscale se vio afectado porque tomó el control manual del checkpointing y lo ejecutó de forma agresiva para realizar copias de seguridad rápidas. Salieron del camino bien establecido, y una carrera de una en mil millones se convirtió en un evento mensual.

Lo que haríamos al respecto

Actualice, pero no entre en pánico. Actualice a SQLite 3.51.3 o más reciente, o uno de los retroportados, a su propio ritmo. El problema es que «su versión de SQLite» rara vez es obvia. SQLite está integrado prácticamente en todas partes y usted no lo instala directamente. Se incluye dentro del runtime de su lenguaje, su ORM, su sistema operativo móvil y su plataforma de edge.

En nuestro trabajo nativo para iOS y Android, este es el que es fácil de olvidar. El SQLite del sistema está vinculado a la versión del sistema operativo que ejecutan sus usuarios, no a la versión con la que usted compiló, y usted no puede elegir cuándo actualizan. Si su aplicación hace algo inusual con las conexiones o los checkpoints, como un hilo de sincronización en segundo plano que escribe mientras la interfaz de usuario lee, incluya su propia compilación de SQLite para controlar la versión en lugar de heredar la que viene con el dispositivo. Hemos hecho exactamente eso en aplicaciones de salud offline-first y de IoT, donde un almacén local corrupto significa datos que el usuario nunca podrá recuperar.

En el lado del backend y el edge, compruebe con qué enlaza realmente su driver. A partir de nuestro trabajo con PHP y Docker, la versión de SQLite integrada en una imagen base puede quedar meses por detrás de la versión upstream, y «estamos en la última versión del framework» no le dice nada sobre la biblioteca C que hay debajo. SQLite serverless y de edge, es decir D1, Turso, LiteFS y similares, merece una atención específica, porque estas plataformas dependen en gran medida del modo WAL y del acceso concurrente. Esa es exactamente la forma que necesita este error.

La lección más importante es sobre las copias de seguridad

El detalle que me quedó grabado no es la condición de carrera. Es que Tailscale solo lo notó porque un pipeline separado leía sus copias de seguridad de S3 y ejecutaba PRAGMA integrity_check contra ellas. Sus bases de datos en producción parecían estar bien. La corrupción ya estaba en los archivos que habían estado almacenando para más tarde.

Durante nuestros trabajos de seguridad y pentesting, las copias de seguridad son donde encontramos los mayores agujeros. Los equipos las realizan religiosamente y nunca las restauran. Una copia de seguridad que usted no ha restaurado es una hipótesis, no una red de seguridad. Si almacena archivos SQLite, ejecute PRAGMA integrity_check sobre una copia de forma periódica, y restáurela en un entorno de prueba de vez en cuando. La corrupción que solo aparece el día que necesita la copia de seguridad es la peor manera de aprender esto.

Una cosa más del artículo que es fácil pasar por alto. Después de que Tailscale desplegara la corrección, un cambio de redondeo en la versión desencadenó falsas advertencias de corrupción en bases de datos que usaban índices de expresión. Lo detectaron porque primero desplegaron en unos pocos fragmentos canary y luego en el resto. Los despliegues por fases no son burocracia. Son la manera de encontrar el segundo error que introdujo la corrección del primero.

Lo que puede hacer esta semana

Averigüe qué versión de SQLite ejecutan realmente sus sistemas en producción y sus aplicaciones publicadas. No la versión del framework, sino la biblioteca SQLite real. Luego elija una copia de seguridad y compruebe que puede restaurarla correctamente. Es una tarde de trabajo, y para la mayoría de los equipos vale más que la propia actualización.

Si rastrear qué versión de SQLite ejecutan realmente sus aplicaciones y servicios, y si sus copias de seguridad sobrevivirían a una restauración, le resulta familiar, hablemos.

databasesexpert-analysissoftware-developmentsqlitetech-news