Menu

Errores comunes en SQLite y cómo solucionarlos

Los errores de SQLite que de verdad vas a encontrarte: database is locked, readonly database, disk image malformed, fallos de constraints… y cómo resolverlos.

Esta página incluye editores ejecutables: edita, ejecuta y ve el resultado al instante.

Los errores son solo SQLite tratando de decirte algo

Los mensajes de error de SQLite son cortos y, a veces, crípticos, pero todos se reducen a un conjunto pequeño de problemas de fondo. La mayoría de los errores comunes de SQLite que vas a encontrar en producción caen en cinco grupos: bloqueos, permisos, corrupción, desajustes de esquema y violaciones de restricciones. En esta página repasamos cada uno: qué lo dispara, qué significa realmente y cómo solucionarlo.

Las cadenas de error vienen acompañadas de códigos numéricos (los códigos extendidos son todavía más específicos). En los logs vas a ver ambas formas:

Error: database is locked          -- código 5 (SQLITE_BUSY)
Error: unable to open database     -- código 14 (SQLITE_CANTOPEN)
Error: attempt to write a readonly -- código 8 (SQLITE_READONLY)
Error: database disk image is      -- código 11 (SQLITE_CORRUPT)

Conocer el código ayuda mucho a la hora de buscar soluciones: SQLITE_BUSY arroja resultados bastante más útiles que el mensaje en inglés a secas.

database is locked (SQLITE_BUSY)

Es el error más típico de SQLite en cualquier aplicación que escriba desde más de un sitio. SQLite serializa las escrituras: solo una conexión puede mantener el bloqueo de escritura al mismo tiempo. Si un segundo proceso intenta escribir y no consigue el bloqueo dentro del busy timeout, te salta este error.

Tres soluciones, ordenadas según el impacto que tienen:

WAL mode por sí solo resuelve el problema de bloqueos en la mayoría de los casos. El busy timeout es tu red de seguridad para la contención real al escribir. Más allá de la configuración, revisa tu código: una transacción que queda abierta mientras el programa hace I/O de red mantendrá el bloqueo durante todo ese tiempo. Mantén las transacciones cortas y haz COMMIT (o ROLLBACK) en cuanto termine el trabajo.

unable to open database file (SQLITE_CANTOPEN)

SQLite intentó abrir el archivo y el sistema operativo le dijo que no. La ruta del archivo o su directorio es el problema el 95% de las veces:

-- Cosas que comprobar:
-- 1. ¿Existe la ruta?                ls -l /ruta/a/db.sqlite
-- 2. ¿Existe el directorio padre?    SQLite crea el archivo
--    pero no el directorio que lo contiene.
-- 3. ¿El usuario que ejecuta tu proceso tiene permisos de
--    lectura+escritura sobre el directorio (no solo sobre el archivo)?
-- 4. ¿El volumen está montado, no está lleno y no es de solo lectura?

Un caso sutil: SQLite necesita crear archivos auxiliares (-journal, -wal, -shm) junto a la base de datos. Si el archivo en sí tiene permisos de escritura pero el directorio no, las aperturas funcionan y las escrituras fallan. Concede siempre permisos de escritura a nivel de directorio.

attempt to write a readonly database (SQLITE_READONLY)

Un pariente cercano del error anterior. El archivo se abre sin problemas, pero las escrituras fallan. Estas son las causas, ordenadas por frecuencia:

  • El usuario del sistema operativo no tiene permisos de escritura sobre el archivo o su directorio.
  • La conexión se abrió con una bandera de solo lectura (SQLITE_OPEN_READONLY, o mode=ro en una URI).
  • El volumen está montado como solo lectura (algo habitual con los bind mounts de Docker y ciertos sistemas de archivos en la nube).
  • La base de datos está en un sistema de archivos de red que no admite el tipo de bloqueos que SQLite necesita.

Corrige los permisos o vuelve a montar el volumen. Si estás en Docker, asegúrate de que el bind mount no sea :ro y de que el usuario del contenedor sea dueño del directorio.

database disk image is malformed (SQLITE_CORRUPT)

Los bytes del archivo ya no coinciden con el formato que espera SQLite. Las causas reales casi siempre son del entorno: procesos que se mataron a mitad de una escritura en sistemas de archivos sin un fsync adecuado, copiar la base de datos mientras había un escritor activo, fallos de hardware o sincronizar el archivo con Dropbox/iCloud.

Primero, confirma el daño:

Si integrity_check devuelve ok, la base de datos está bien y el error viene de otro lado (lo más habitual: una conexión obsoleta). Si en cambio te devuelve una lista de problemas, toca recuperar los datos.

La forma más limpia de recuperación es usar el comando .recover de la CLI, que extrae todo lo que puede salvar y lo vuelca en una base de datos nueva:

sqlite3 corrupt.db ".recover" | sqlite3 recovered.db
sqlite3 recovered.db "PRAGMA integrity_check;"

Si tienes una copia de seguridad reciente, restaura desde ella; es más rápido y te evitas la ambigüedad del típico "recuperamos casi todo". Échale un vistazo a la página de backup y restauración para ver la forma correcta de copiar una base de datos en uso (pista: nada de cp).

no such table y no such column en SQLite

Estos errores comunes de SQLite significan justo lo que dicen, pero la causa suele reducirse a dos: o estás conectado a una base de datos distinta a la que crees, o una migración no llegó a ejecutarse.

Revisa la cadena de conexión de tu aplicación: las rutas relativas se resuelven contra el directorio de trabajo actual, que cambia según si estás en la terminal, en el IDE o en el proceso de producción. Una base de datos en memoria (:memory:) arranca vacía cada vez, y eso confunde a más de uno cuando espera que los datos persistan.

El uso de comillas en los identificadores también importa. Los nombres sin comillas no distinguen entre mayúsculas y minúsculas, pero "User" y "user" son identificadores distintos. Si creaste una tabla poniéndole comillas al nombre, vas a tener que seguir citándola siempre.

Violaciones de restricciones (constraints)

SQLite rechaza cualquier escritura que rompa una restricción. El mensaje de error te dice exactamente cuál:

Cada fallo corresponde a un código distinto por debajo (SQLITE_CONSTRAINT_UNIQUE, SQLITE_CONSTRAINT_CHECK, SQLITE_CONSTRAINT_NOTNULL). La solución casi siempre está en la capa de aplicación: valida los datos antes de escribir, o usa INSERT ... ON CONFLICT para gestionar los duplicados de forma intencionada.

El error foreign key constraint failed en SQLite merece mención aparte: las claves foráneas vienen desactivadas por defecto. Si no las activas, las referencias inválidas entran sin avisar y revientan más tarde, justo cuando por fin habilitas la comprobación. Define el pragma en cada conexión:

cannot start a transaction within a transaction

Llamaste a BEGIN cuando ya había una transacción abierta. SQLite no admite transacciones anidadas, pero sí permite anidar savepoints, lo que te da el mismo efecto en la práctica:

Si tu ORM o framework gestiona las transacciones, lo más probable es que le hayas pedido iniciar una dos veces. Revisa si el autocommit está activo y si tu pool de conexiones está reutilizando una conexión que ya tiene una transacción abierta.

disk I/O error (SQLITE_IOERR)

El sistema operativo rechazó una lectura o escritura. Disco lleno, un tropiezo del sistema de archivos en red, o el archivo desapareció justo debajo de SQLite. Lo primero que conviene mirar es df -h. Lo segundo es si la base de datos está en algo poco confiable como NFS o una carpeta sincronizada con la nube — SQLite da por hecho un sistema de archivos POSIX local con un fsync que funcione. Si no puedes moverla de ahí, asume que el riesgo de corrupción sube.

syntax error near "..."

El parser de SQLite te indica qué token lo dejó descolocado. La solución suele estar tres líneas antes de donde apunta el error: una coma que falta, un identificador sin comillas que choca con una palabra reservada, o una cadena con comillas simples mal escapadas ('it''s', no 'it's').

Usa parameter binding (placeholders ?) para los datos que vienen del usuario en lugar de armar el SQL concatenando strings: te ahorras toda una categoría de errores de sintaxis y, de paso, evitas inyección SQL.

Checklist de diagnóstico

Cuando algo revienta en producción, esta secuencia cubre la mayoría de los casos en menos de un minuto:

Cinco pragmas, cinco respuestas. Combinado con el código de error de la consulta fallida, sabrás a qué categoría pertenece el problema y qué página de la documentación abrir a continuación.

Cerrando el temario

Hasta aquí el recorrido. Empezaste con CREATE TABLE y pasaste por joins, índices, transacciones, modo WAL, copias de seguridad y, ahora, los modos de fallo que aparecen cuando SQLite se enfrenta al mundo real. Los patrones se repiten: transacciones cortas, claves foráneas activadas, modo WAL, copias de seguridad periódicas y un sano respeto por PRAGMA integrity_check. Mantén esos hábitos y SQLite seguirá funcionando en silencio durante años.

Preguntas frecuentes

¿Por qué SQLite me devuelve 'database is locked'?

Otra conexión tiene tomado el bloqueo de escritura y la tuya agotó el tiempo de espera. Lo que suele funcionar: activar el modo WAL con PRAGMA journal_mode=WAL para que las lecturas no bloqueen las escrituras, subir el timeout con PRAGMA busy_timeout = 5000 y asegurarte de hacer commit cuanto antes en lugar de dejar transacciones abiertas.

¿Cómo se arregla 'attempt to write a readonly database' en SQLite?

Casi siempre es un problema de permisos del sistema de archivos, no de SQLite. El usuario con el que corre tu proceso necesita permisos de escritura tanto en el fichero de la base de datos como en el directorio que lo contiene (SQLite crea ahí los ficheros auxiliares -journal o -wal). Revisa el propietario, los permisos y que el volumen no esté montado como solo lectura.

¿Qué significa 'database disk image is malformed'?

SQLite ha leído bytes que no encajan con el formato esperado, normalmente por corrupción: procesos matados a la fuerza, discos defectuosos o copiar el fichero mientras estaba abierto. Confirma con PRAGMA integrity_check y luego usa .recover desde la CLI para volcar lo recuperable a una base de datos nueva. Si tienes backup, restaurar es mucho más rápido.

¿Por qué me sale 'no such table' o 'no such column'?

Estás conectado a un fichero distinto del que crees, o no se ejecutó alguna migración. Mira PRAGMA database_list para ver qué ruta abrió SQLite realmente y .schema nombre_tabla para ver las columnas auténticas. También son habituales los typos y diferencias de mayúsculas: SQLite no distingue mayúsculas en identificadores sin comillas, pero sí cuando van entrecomillados.

Coddy programming languages illustration

Aprende a programar con Coddy

COMENZAR