O código de erro do Firebird é onde o diagnóstico costuma travar: 335544345 não diz nada e o log guarda só a primeira linha da mensagem. Quase todo erro em produção cai em quatro famílias — conexão, concorrência, dados e sintaxe — e cada família tem um caminho de investigação próprio.
O que significam os números de erro do Firebird?
O Firebird devolve sempre dois códigos diferentes para o mesmo problema: o SQLCODE (negativo, como -104) e o GDSCODE (um número longo, como 335544569). O texto da mensagem mostra os dois no final, e é por isso que a mesma falha aparece com números diferentes dependendo do driver.
-- Mensagem completa, como o Firebird devolve
Dynamic SQL Error
SQL error code = -104
Token unknown - line 1, column 8
SELEC
Traduzindo: Dynamic SQL Error é o GDSCODE 335544569 (erro genérico de SQL preparado em tempo de execução) e -104 é o SQLCODE específico (token inesperado). Se o log guarda só o primeiro número, você perde a informação que resolve o caso.
| Código | Mensagem | Família | Causa mais comum |
|---|---|---|---|
| 335544721 | unable to complete network request to host | Conexão | Servidor fora, porta 3050 bloqueada, DNS errado |
| 10054 | connection reset by peer | Conexão | Rede caiu, firewall derrubou a sessão ociosa, serviço reiniciado |
| 335544375 | unavailable database | Conexão/config | Caminho errado, arquivo sem permissão, banco em restore |
| 335544569 | dynamic SQL error | Sintaxe | Query montada por concatenação com aspas erradas |
| 335544665 | violation of PRIMARY or UNIQUE KEY constraint | Dados | Duplicidade, generator atrasado, retry sem idempotência |
| 335544578 | validation error for column, value "*** null ***" | Dados | Coluna NOT NULL recebendo NULL |
| 335544382 | string right truncation | Dados | Valor maior que o VARCHAR da coluna |
| 335544345 | lock conflict on no wait transaction | Concorrência | Transação NO WAIT disputando a mesma linha |
| 335544336 | deadlock | Concorrência | Duas transações atualizando as mesmas tabelas em ordem inversa |
| -902 | internal Firebird consistency check | Motor | Bug conhecido da versão ou corrupção de página |
Essa tabela cobre a maior parte do que aparece em log de sistema legado. Vale mapear apenas os códigos que realmente ocorrem no seu ambiente — mapear os 2.000 códigos possíveis é trabalho sem retorno.
Por que aparece "error writing data to the connection"?
Esse texto não é um erro de SQL: ele indica que a conexão TCP morreu no meio do comando. O driver recebeu um socket fechado e o Firebird não conseguiu escrever a resposta.
As causas reais, em ordem de frequência:
- Firewall ou NAT derrubando conexão ociosa. Pool de conexão que fica 30 minutos parado e volta a usar é o caso clássico.
- Serviço do Firebird reiniciado durante o deploy ou por crash.
fbclient.dllincompatível com a versão do servidor, ou 32 bits em processo de 64 bits.- Rede instável em link VPN/WAN entre aplicação e banco.
- Timeout de rede menor que a duração da query (relatório longo que ninguém vê falhar até o fim).
Diagnóstico rápido: rode isql do mesmo servidor de aplicação para o host do banco. Se funciona no seu micro e falha na máquina da aplicação, o problema é infraestrutura, não código.
Como classificar o erro antes de tratá-lo?
Classifique por SQLSTATE, não por texto. A classe 08 do padrão SQL significa "connection exception" e é a única família em que repetir a operação faz sentido.
// PDO: separe erro de conexão (retry) de erro de dados (não repita)
try {
$stmt = $pdo->prepare('INSERT INTO pedidos (cliente_id, valor) VALUES (?, ?)');
$stmt->execute([$clienteId, $valor]);
} catch (PDOException $e) {
$state = $e->errorInfo[1] ?? null; // classe SQLSTATE
$msg = $e->errorInfo[2] ?? $e->getMessage();
error_log(sprintf('sqlstate=%s gdscode=%s msg=%s sql=%s',
$e->getCode(), $state, $msg, $stmt->queryString));
if ($e->getCode() === '08006' || $e->getCode() === '08003') {
// conexão caiu: reconectar e repetir uma vez
return $this->executarComReconexao($sqlOriginal, $params);
}
throw $e; // unique key, truncation, validation: repetir não resolve
}
Repetir um 335544665 (unique key) só gera mais erro e mais log. Repetir um 08006 resolve a maior parte das falhas de rede — desde que a operação seja idempotente.
Como funciona no driver legado ibase_*?
Nas extensões interbase/ibase (ainda comuns em PHP 5 e 7 antigos), o código vem em funções separadas. Guardar apenas ibase_errmsg() perde o número e impede classificação automática.
$conn = ibase_connect($dsn, $user, $pass, 'UTF8', 0, 3);
$res = @ibase_query($conn, $sql);
if ($res === false) {
error_log(json_encode([
'errcode' => ibase_errcode(), // GDSCODE numérico
'errmsg' => ibase_errmsg(), // mensagem completa
'sql' => $sql,
'user' => $_SESSION['usuario'] ?? 'cli',
], JSON_UNESCAPED_UNICODE));
}
Com o GDSCODE em mão, a classificação vira switch ($code) e a mensagem técnica nunca precisa chegar à tela do usuário.
Como descobrir qual constraint violou a unique key?
A mensagem já entrega o nome do constraint e da tabela, mas o nome costuma ser gerado (INTEG_23) e não diz qual coluna duplicou. A consulta abaixo traduz o identificador em colunas reais.
-- Troque INTEG_23 pelo nome que apareceu na mensagem de erro
SELECT
rc.RDB$RELATION_NAME AS tabela,
isg.RDB$FIELD_NAME AS coluna,
rc.RDB$CONSTRAINT_TYPE AS tipo
FROM RDB$RELATION_CONSTRAINTS rc
JOIN RDB$INDEX_SEGMENTS isg
ON isg.RDB$INDEX_NAME = rc.RDB$INDEX_NAME
WHERE rc.RDB$CONSTRAINT_NAME = 'INTEG_23'
ORDER BY isg.RDB$FIELD_POSITION;
Com a tabela e a coluna em mãos, o próximo passo é sempre o mesmo: verificar se o generator está sincronizado com o MAX(id). Esse desalinhamento é a causa mais comum de unique key em sistema que roda há anos — e tem solução própria.
Escrever consulta de diagnóstico contra RDB$ no meio do incidente é onde se perde tempo. O Sqlify transforma a descrição em português na query pronta, com cada cláusula explicada.
Como reproduzir o erro fora de produção?
Reproduzir com isql separa problema de banco de problema de aplicação. Dialect 3 é o padrão do Firebird moderno; um cliente conectando em dialect 1 muda o comportamento de datas e de NUMERIC.
# Conecta no banco remoto e deixa a sessão aberta
isql -user SYSDBA -password sua_senha 10.0.0.15/3050:/dados/empresa.fdb
SQL> SET SQL DIALECT 3;
SQL> SELECT CURRENT_TRANSACTION FROM RDB$DATABASE; -- transação aberta
SQL> SELECT COUNT(*) FROM clientes;
Se o mesmo comando funciona no isql e falha na aplicação, o problema está no driver, no pool ou na query que a aplicação monta — quase sempre concatenação de string.
Como ver quem está segurando a conexão?
O monitor do Firebird (MON$) fica disponível a partir da versão 2.1 e mostra conexões e transações vivas sem instalar nada. É a primeira pergunta a fazer quando o erro é de concorrência.
SELECT a.MON$ATTACHMENT_ID, a.MON$USER, a.MON$REMOTE_ADDRESS,
t.MON$TRANSACTION_ID, t.MON$TIMESTAMP, t.MON$LOCK_TIMEOUT
FROM MON$ATTACHMENTS a
JOIN MON$TRANSACTIONS t ON t.MON$ATTACHMENT_ID = a.MON$ATTACHMENT_ID
WHERE t.MON$STATE = 1 -- 1 = transação ativa
ORDER BY t.MON$TIMESTAMP;
Uma transação ativa há horas, de um usuário que já saiu do sistema, explica tanto lock conflict quanto crescimento de versões de registro. O detalhamento desse diagnóstico está em monitorar queries lentas no Firebird.
Checklist: o que ter antes do próximo incidente
- Log registrando SQLSTATE, GDSCODE, query e usuário — sem valores de bind
- Mensagem técnica nunca exibida ao usuário final
- Retry automático apenas para a classe
08(conexão) -
fbclientde 32/64 bits igual ao processo PHP - Acesso ao
MON$pronto para uso em incidente -
gfix -validateagendado em rotina de manutenção - Versão do Firebird anotada e com patch disponível
Para corrupção suspeita (SQLCODE -902), o caminho é gfix -validate -full com o banco offline:
# Banco deve estar parado; validate não corrige, só aponta
gfix -validate -full -user SYSDBA -password sua_senha /dados/empresa.fdb
Se o -902 aparece sempre no mesmo trecho de código, procure no changelog da sua versão: costuma ser bug do motor já corrigido em release posterior.
Perguntas frequentes
O que é o erro 902 do Firebird?
SQLCODE -902 é internal Firebird consistency check: o motor encontrou um estado que não deveria existir. Não é erro de SQL e não se resolve reescrevendo a query. Trate como sinal de bug da versão ou de corrupção de página: atualize o Firebird, rode gfix -validate -full e compare o resultado antes de qualquer restore.
O erro 10054 é do Firebird?
Não. O 10054 é WSAECONNRESET do Winsock: a conexão TCP foi encerrada pelo outro lado. O Firebird só repassa o que a camada de rede informou. A investigação é de infraestrutura — firewall, NAT, reinício do serviço, VPN.
O que significa o erro 104?
SQL error code = -104 é erro de sintaxe na query dinâmica: token inesperado, palavra reservada usada como nome de coluna, aspas simples não escapadas. Quando aparece em produção e não em teste, quase sempre é uma query montada por concatenação com valor contendo apóstrofo. O uso de bind parameters resolve a causa e ainda fecha a porta para SQL injection.
Por que o mesmo erro tem números diferentes entre versões?
O Firebird reorganizou parte da tabela de mensagens na versão 3.0, então o GDSCODE de uma falha pode mudar entre 2.5 e 3.0. Por isso a classificação confiável é pelo SQLSTATE (-104, -901, -904, classe 08), que segue o padrão SQL, e não pelo número longo.
Conclusão
Erro do Firebird se resolve em duas etapas: identificar a família (conexão, concorrência, dados ou sintaxe) e só então olhar o detalhe. Log com SQLSTATE e GDSCODE completo elimina metade da investigação, e MON$ responde o resto. O Sqlify traduz a descrição em português para a query pronta, com cada cláusula explicada — inclusive para quem precisa montar o diagnóstico em SQL.
Leia também: