Error de PostgreSQL: canceling statement due to statement timeout
ERROR: canceling statement due to statement timeout
La sentencia se ejecutó durante más tiempo del que permite statement_timeout, medido en tiempo de reloj desde que el servidor la recibió — incluido cualquier tiempo pasado esperando bloqueos. PostgreSQL la canceló y revirtió sus efectos.
Qué significa este error
El SQLSTATE 57014 (query_canceled) cubre todas las cancelaciones de sentencias; el mensaje te dice cuál te tocó:
due to statement timeout— esta página:statement_timeoutexpiró.due to user request— alguien pulsó Ctrl+C o llamó apg_cancel_backend().due to lock timeout— un ajuste distinto (lock_timeout) y un SQLSTATE distinto (55P03): la sentencia se rindió esperando un bloqueo.
El matiz que importa: statement_timeout cuenta también las esperas de bloqueo. Una consulta que normalmente tarda 50 ms puede alcanzar un timeout de 30 s porque se quedó detrás del ALTER TABLE de alguien. Antes de "optimizar" la consulta, averigua en qué caso estás.
Causas comunes
- Una consulta genuinamente lenta: índice faltante, un plan que cambió tras el crecimiento de los datos o estadísticas desactualizadas, un escaneo sin acotar.
- Bloqueada en un lock: la consulta estaba bien pero esperó detrás de un DDL o de una transacción de escritura larga.
- El timeout está configurado más bajo de lo que crees — globalmente en
postgresql.conf, por rol o base de datos (ALTER ROLE ... SET statement_timeout), por sesión por el driver/ORM, o por transacción. Estos se anulan entre sí y es fácil perder la cuenta. - Un trabajo por lotes o una migración que legítimamente necesita minutos, ejecutándose bajo un timeout de tamaño OLTP.
Cómo diagnosticarlo
-- De dónde viene el valor activo:
SELECT name, setting, source
FROM pg_settings
WHERE name = 'statement_timeout';
-- Overrides por rol/base de datos:
SELECT * FROM pg_db_role_setting;
La sentencia cancelada se escribe en el log del servidor junto con el error, así que sabes exactamente cuál era la consulta. Luego separa los dos casos:
- Ejecútala con
EXPLAIN (ANALYZE, BUFFERS)en un contexto seguro y mira dónde se va el tiempo — pega el JSON en el visualizador de EXPLAIN y revisa los nodos más lentos y las advertencias de estimación de filas. - Si se reproduce en vivo, comprueba
wait_event_type/wait_eventenpg_stat_activitymientras se ejecuta:Locksignifica que es un problema de bloqueo, no un problema de velocidad de la consulta.
Cómo solucionarlo
- Consulta lenta → arregla la consulta o la indexación; esa es la solución real, el timeout solo la sacó a la superficie.
- Operación larga legítima → acota la excepción en vez de subir el valor global:
BEGIN; SET LOCAL statement_timeout = '30min'; -- vale solo para esta transacción -- ... migración o informe ... COMMIT; - Esperas de bloqueo → usa
lock_timeoutpara el DDL de modo que falle rápido en vez de encolarse (y bloquear a todos los que están detrás), y busca la transacción larga que sostenía el bloqueo. - Mantén un tope global razonable. Un
statement_timeoutglobal modesto es protección contra consultas descontroladas; la respuesta a un falso positivo es un override acotado, no desactivarlo.
