Menu

Erros comuns do SQLite: database is locked, readonly e mais

Os erros do SQLite que você realmente vai encontrar em produção — database is locked, readonly database, disk image malformed e falhas de constraint — e como resolver cada um.

Esta página tem editores executáveis — edite, execute e veja a saída na hora.

Erros são só o SQLite avisando alguma coisa

As mensagens de erro do SQLite são curtas e, às vezes, meio enigmáticas, mas todas remetem a um conjunto pequeno de problemas reais. Na prática, quase tudo que você vai encontrar em produção cai em cinco categorias: travamento (locking), permissões, corrupção, descompasso de schema e violação de constraints. Esta página percorre cada uma delas — o que dispara o erro, o que ele realmente significa e como resolver.

As strings de erro vêm acompanhadas de códigos numéricos (e os códigos estendidos são ainda mais específicos). Você vai ver as duas formas nos logs:

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)

Saber o código ajuda muito na hora de pesquisar — buscar por SQLITE_BUSY traz resultados bem melhores do que a mensagem em inglês pura.

database is locked (SQLITE_BUSY)

Esse é o erro mais comum do SQLite em qualquer aplicação que escreve de mais de um lugar ao mesmo tempo. O SQLite serializa as escritas: só uma conexão consegue segurar o lock de escrita por vez. Se um segundo escritor não conseguir o lock dentro do tempo do busy timeout, é aí que aparece o database is locked.

Três soluções, em ordem de impacto:

O modo WAL sozinho já resolve o problema de travamento na maior parte dos cenários. Já o busy timeout é a sua rede de segurança quando há disputa real por escrita. Além das configurações, revise seu código: uma transação que fica aberta enquanto o programa faz I/O de rede vai segurar o lock durante todo esse tempo. Mantenha as transações curtas e faça COMMIT (ou ROLLBACK) assim que o trabalho terminar.

unable to open database file (SQLITE_CANTOPEN)

O SQLite tentou abrir o arquivo e o sistema operacional negou. Em 95% dos casos, o problema está no caminho do arquivo ou no diretório onde ele deveria estar:

-- Coisas para verificar:
-- 1. O caminho existe?               ls -l /path/to/db.sqlite
-- 2. O diretório pai existe? O SQLite cria o arquivo
--    mas não o diretório acima dele.
-- 3. O usuário que está executando o processo tem permissão
--    de leitura+escrita no diretório (não apenas no arquivo)?
-- 4. O volume está montado, não está cheio e não é somente leitura?

Um caso sutil: o SQLite precisa criar arquivos auxiliares (-journal, -wal, -shm) ao lado do banco. Se o arquivo em si tem permissão de escrita, mas o diretório não, a abertura funciona e a escrita falha. Sempre garanta permissão de escrita no nível do diretório.

attempt to write a readonly database (SQLITE_READONLY)

Esse erro é primo próximo do anterior. O arquivo abriu sem problema, mas as escritas falham. As causas, da mais comum à menos comum:

  • O usuário do SO não tem permissão de escrita no arquivo ou no diretório.
  • A conexão foi aberta com a flag de somente leitura (SQLITE_OPEN_READONLY, ou mode=ro na URI).
  • O volume está montado como somente leitura (algo comum em bind mounts do Docker e em alguns sistemas de arquivos na nuvem).
  • O banco está em um sistema de arquivos de rede que não suporta o tipo de locking que o SQLite precisa.

Ajuste as permissões ou remonte o volume. Se você estiver usando Docker, confira se o bind mount não está como :ro e se o usuário do container é o dono do diretório.

database disk image is malformed (SQLITE_CORRUPT)

Os bytes do arquivo não batem mais com o formato esperado pelo SQLite. Na prática, as causas costumam ser ambientais: processos mortos no meio de uma escrita em sistemas de arquivos sem fsync adequado, cópia do banco enquanto havia um writer ativo, falhas de hardware ou sincronização do arquivo por Dropbox/iCloud.

Antes de qualquer coisa, confirme o estrago:

Se o integrity_check devolver ok, seu banco está íntegro e o erro veio de outro lugar (normalmente uma conexão zumbi que ficou pendurada). Já se aparecer uma lista de problemas, é hora de partir para a recuperação.

O caminho mais limpo de recuperação é usar o comando .recover da CLI, que extrai tudo que conseguir salvar para um banco novinho em folha:

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

Se você tem um backup recente, restaure a partir dele — é mais rápido e evita aquela dúvida do "será que recuperei tudo mesmo?". Dê uma olhada na página sobre backup e restauração para entender a forma correta de copiar um banco de dados em uso (dica: nada de cp).

Erros no such table e no such column

Esses erros significam exatamente o que dizem, mas a causa costuma ser uma de duas coisas: você está conectado a um banco diferente do que imagina, ou alguma migration não rodou.

Confira a connection string da sua aplicação — caminhos relativos são resolvidos a partir do diretório de trabalho atual, que muda entre o seu terminal, a sua IDE e o processo em produção. Já um banco em memória (:memory:) começa zerado a cada execução, o que confunde quem esperava que os dados fossem persistidos.

A forma de citar identificadores também faz diferença. Nomes sem aspas são case-insensitive, mas "User" e "user" são identificadores distintos. Se você criou a tabela com aspas no nome, vai precisar continuar usando aspas sempre que referenciá-la.

Violações de constraint

O SQLite rejeita qualquer escrita que quebre uma constraint. A mensagem de erro indica qual delas foi violada:

Cada falha tem um código diferente por baixo dos panos (SQLITE_CONSTRAINT_UNIQUE, SQLITE_CONSTRAINT_CHECK, SQLITE_CONSTRAINT_NOTNULL). A correção quase sempre mora na camada da aplicação — valide a entrada antes de gravar, ou use INSERT ... ON CONFLICT para tratar duplicatas de forma intencional.

O FOREIGN KEY constraint failed merece um parágrafo só dele: no SQLite, as foreign keys vêm desligadas por padrão. Se você não ativar, referências inválidas entram em silêncio e só explodem depois, quando você finalmente liga a verificação. Defina o pragma em toda conexão:

cannot start a transaction within a transaction

Esse é um dos erros sqlite mais comuns quando se mexe com transações: você chamou BEGIN enquanto já havia uma transação aberta. O SQLite não permite transações aninhadas — mas aceita savepoints aninhados, que entregam o mesmo resultado na prática:

Se o seu ORM ou framework cuida das transações, é bem provável que você tenha mandado abrir uma duas vezes. Confira se o autocommit está ligado e se o seu pool de conexões não está reaproveitando uma conexão que já tem uma transação aberta.

disk I/O error (SQLITE_IOERR)

O sistema operacional recusou uma leitura ou escrita. Disco cheio, problema momentâneo num sistema de arquivos em rede, ou o arquivo foi apagado por baixo dos panos do SQLite. A primeira coisa a verificar é o df -h. A segunda é se o banco mora em algo instável, tipo NFS ou pasta sincronizada com a nuvem — o SQLite parte do princípio de que está num sistema de arquivos POSIX local com fsync funcionando. Se não der para tirar dali, saiba que o risco de corrupção aumenta.

syntax error near "..."

O parser do SQLite mostra qual token deixou ele confuso. Na prática, o erro costuma estar umas três linhas antes do ponto apontado — uma vírgula faltando, um identificador sem aspas que bate com uma palavra-chave reservada, ou uma string com aspas simples que precisam ser escapadas ('it''s', e não 'it's').

Use parameter binding (placeholders ?) para entradas do usuário em vez de montar SQL concatenando strings — você evita uma categoria inteira de erros de sintaxe e, de quebra, ainda fecha a porta para SQL injection.

Checklist de diagnóstico

Quando algo quebra em produção, essa sequência resolve a maioria dos casos em menos de um minuto:

Cinco pragmas, cinco respostas. Combinando isso com o código de erro da consulta que falhou, você consegue identificar em qual categoria o problema se encaixa e qual página da documentação abrir em seguida.

Encerrando o currículo

E é isso, terminamos a jornada. Você partiu do CREATE TABLE e passou por joins, índices, transações, modo WAL, backups e, agora, pelos erros do SQLite que aparecem quando o banco encontra o mundo real. Os padrões se repetem: transações curtas, foreign keys habilitadas, modo WAL, backups regulares e um respeito saudável pelo PRAGMA integrity_check. Mantenha esses hábitos e o SQLite vai rodar quietinho por anos a fio.

Perguntas frequentes

Por que o SQLite retorna 'database is locked'?

Outra conexão está segurando um lock de escrita e a sua estourou o tempo de espera. As soluções mais comuns são: ativar o modo WAL com PRAGMA journal_mode=WAL para que leitores não bloqueiem escritores, aumentar o busy timeout com PRAGMA busy_timeout = 5000 e garantir que você está fazendo commit das transações na hora certa, sem deixá-las abertas.

Como corrigir 'attempt to write a readonly database' no SQLite?

Quase sempre é problema de permissão de arquivo, não do SQLite em si. O usuário do SO que executa o seu processo precisa ter permissão de escrita tanto no arquivo do banco quanto no diretório onde ele está (o SQLite cria arquivos auxiliares como -journal ou -wal ali). Confira o dono do arquivo, as permissões e se o volume não está montado como somente leitura.

O que significa 'database disk image is malformed'?

O SQLite leu bytes que não batem com o formato esperado — geralmente por corrupção causada por processo morto na marra, disco com defeito ou cópia do arquivo enquanto ele estava aberto. Rode PRAGMA integrity_check para confirmar e use .recover no CLI para extrair o que ainda dá pra salvar para um banco novo. Se você tiver backup, restaurar é bem mais rápido.

Por que aparece 'no such table' ou 'no such column'?

Você está conectado num arquivo de banco diferente do que imagina, ou alguma migration não rodou. Use PRAGMA database_list para ver o caminho do arquivo que o SQLite realmente abriu, e .schema nome_tabela para ver as colunas de verdade. Vale conferir também se não tem erro de digitação ou diferença de maiúsculas/minúsculas — o SQLite é case-insensitive para identificadores sem aspas, mas não para os que estão entre aspas.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR