Esse erro vem do PostgreSQL e significa o seguinte:
“cached plan must not change result type (SQLSTATE 0A000)”
- O PostgreSQL cria planos de execução em cache para consultas parametrizadas (principalmente em prepared statements ou queries vindas de drivers de ORM).
- Esses planos em cache assumem que a consulta sempre retornará o mesmo conjunto de colunas e tipos.
- Se, por algum motivo, a mesma query (ou o mesmo statement preparado) puder retornar tipos diferentes em execuções diferentes, o Postgres acusa erro.
- Funções que retornam tipo polimórfico ou
anyelement– se em uma execução retornaminte em outratext, quebra. - Uso de
UNIONouCASEsem coerção explícita – se em uma execução o otimizador inferir um tipo diferente. - Views ou funções com
RETURN RECORD– se a estrutura muda entre chamadas. - Consultas que dependem de parâmetros para definir o tipo de saída – ex.:
PREPARE my_stmt AS SELECT $1; -- Tipo do parâmetro influencia o tipo de saída EXECUTE my_stmt(1); -- inteiro EXECUTE my_stmt('abc'); -- texto → erro
- ORMs (tipo Hibernate, Sequelize, etc.) – que reaproveitam o mesmo statement com parâmetros diferentes, causando mudança de tipo inferido.
- Forçar casting explícito em colunas/valores para que o tipo não varie:
SELECT CASE WHEN cond THEN 'A' ELSE 'B' END::text;
- Evitar funções polimórficas sem cast; se usar, force o retorno:
SELECT myfunc($1)::int;
- Revisar prepared statements no app/ORM: talvez precise invalidar o plano ao mudar o tipo do parâmetro.
EXECUTEcom tipos consistentes: sempre usar parâmetros coerentes.- Em casos específicos, desativar plan caching no ORM (ou usar query nativa).
-- Isso pode gerar erro em planos em cache:
SELECT CASE WHEN true THEN 1 ELSE 'texto' END;
-- Correto (com cast explícito):
SELECT CASE WHEN true THEN 1::text ELSE 'texto' END;-- Pode falhar se o Postgres tentar cachear o plano:
SELECT 1
UNION ALL
SELECT 'abc';
-- Correto (forçando coerção):
SELECT 1::text
UNION ALL
SELECT 'abc';-- Suponha uma função que retorna anyelement
PREPARE stmt AS SELECT myfunc($1);
EXECUTE stmt(1); -- retorna inteiro
EXECUTE stmt('texto'); -- quebra, pois o tipo mudouCorreção:
PREPARE stmt AS SELECT myfunc($1)::text;👉 Resumo:
Esse erro acontece porque o PostgreSQL detectou que um statement em cache que deveria ter sempre o mesmo tipo de saída mudou entre execuções.
A solução é garantir consistência de tipos (com casts) ou ajustar o uso de prepared statements.