El incidente de Tailscale fue causado por un data race extremadamente raro y de larga data (16+ años) en el proceso de checkpointing de SQLite, denominado 'WAL-Reset bug'. Este bug ocurría cuando una transacción de escritura coincidía con un checkpoint en un momento específico, llevando al checkpoint a creer erróneamente que ciertas páginas del WAL habían sido copiadas a la base de datos principal, cuando en realidad no lo habían sido. Esto resultaba en la pérdida permanente de datos y la corrupción del archivo de la base de datos, ya que otras páginas (como índices) que referenciaban los datos perdidos sí se escribían.
La arquitectura de Tailscale, que utiliza SQLite con un control manual y agresivo del proceso de checkpointing para optimizar backups, aumentó la probabilidad de encontrar este bug. Aunque SQLite es una "tecnología aburrida" y confiable, desviarse del camino operacional estándar, incluso con configuraciones documentadas, introdujo una condición de carrera que rara vez se manifestaba en otros entornos. Las salvaguardas iniciales fallaron porque el bug era indetectable con las herramientas de monitoreo y diagnóstico existentes, y su naturaleza intermitente y sin patrones claros dificultó la reproducción y el aislamiento.
La investigación fue un proceso forense prolongado y complejo. La falta de un trigger reproducible obligó a Tailscale a desplegar telemetría pasiva en producción. La colaboración con los desarrolladores de SQLite fue crucial, llevando a la creación de herramientas de depuración especializadas como el shim 'tmstmpvfs'. Este shim, al envolver la capa del Virtual File System de SQLite, permitió registrar información detallada sobre los cambios en la base de datos durante el checkpointing, lo que finalmente expuso la condición de carrera. El descubrimiento de que las escrituras comprometidas desaparecían sin error a través del pipeline de transaction logging fue una pista vital que apuntó hacia un problema fundamental en la persistencia de datos.
Un segundo problema surgió durante el despliegue del parche inicial: un bug relacionado con índices de expresión obsoletos y cambios sutiles en el redondeo de conversiones de texto a float en SQLite 3.52.0. Esto causó falsas alarmas de corrupción. Aunque no fue la causa raíz del incidente principal, demostró la complejidad de las interacciones entre componentes y la necesidad de una validación rigurosa de los cambios, incluso en librerías de terceros. La resolución de ambos problemas, el WAL-Reset bug y el de los índices de expresión, requirió una profunda comprensión de los internos de SQLite y una estrecha colaboración entre Tailscale y los mantenedores de SQLite.