Erreur PostgreSQL : canceling statement due to statement timeout
ERROR: canceling statement due to statement timeout
L'instruction a duré plus longtemps que ne l'autorise statement_timeout, mesuré en temps horloge depuis la réception par le serveur — y compris tout temps passé à attendre des verrous. PostgreSQL l'a annulée et a annulé ses effets.
Ce que signifie cette erreur
Le SQLSTATE 57014 (query_canceled) couvre toutes les annulations d'instruction ; le message vous indique laquelle vous avez eue :
due to statement timeout— cette page :statement_timeouta expiré.due to user request— quelqu'un a appuyé sur Ctrl+C ou appelépg_cancel_backend().due to lock timeout— un paramètre différent (lock_timeout) et un SQLSTATE différent (55P03) : l'instruction a renoncé à attendre un verrou.
La subtilité qui compte : statement_timeout compte aussi les attentes de verrou. Une requête qui prend normalement 50 ms peut atteindre un timeout de 30 s parce qu'elle est restée derrière un ALTER TABLE de quelqu'un. Avant d'« optimiser » la requête, déterminez dans quel cas vous êtes.
Causes fréquentes
- Une requête réellement lente : index manquant, un plan qui a basculé après la croissance des données ou des statistiques obsolètes, un parcours non borné.
- Bloquée sur un verrou : la requête allait bien mais a attendu derrière du DDL ou une longue transaction d'écriture.
- Le timeout est défini plus bas que vous ne le pensez — globalement dans
postgresql.conf, par rôle ou base (ALTER ROLE ... SET statement_timeout), par session par le driver/ORM, ou par transaction. Ces valeurs se surchargent mutuellement et il est facile de s'y perdre. - Un job batch ou une migration qui a légitimement besoin de minutes, s'exécutant sous un timeout dimensionné pour l'OLTP.
Comment la diagnostiquer
-- D'où vient la valeur active :
SELECT name, setting, source
FROM pg_settings
WHERE name = 'statement_timeout';
-- Surcharges par rôle/base :
SELECT * FROM pg_db_role_setting;
L'instruction annulée est écrite dans le journal du serveur avec l'erreur, vous savez donc exactement de quelle requête il s'agissait. Ensuite, séparez les deux cas :
- Exécutez-la avec
EXPLAIN (ANALYZE, BUFFERS)dans un contexte sûr et regardez où part le temps — collez le JSON dans le visualiseur EXPLAIN et examinez les nœuds les plus lents et les avertissements d'estimation de lignes. - Si cela se reproduit en direct, vérifiez
wait_event_type/wait_eventdanspg_stat_activitypendant l'exécution :Locksignifie que c'est un problème de blocage, pas un problème de vitesse de requête.
Comment la corriger
- Requête lente → corrigez la requête ou l'indexation ; c'est la vraie solution, le timeout n'a fait que la révéler.
- Opération longue légitime → cadrez l'exception au lieu d'augmenter la valeur globale :
BEGIN; SET LOCAL statement_timeout = '30min'; -- ne vaut que pour cette transaction -- ... migration ou rapport ... COMMIT; - Attentes de verrou → utilisez
lock_timeoutpour le DDL afin qu'il échoue vite au lieu de faire la queue (et de bloquer tout le monde derrière lui), et traquez la transaction longue qui détenait le verrou. - Gardez un plafond global raisonnable. Un
statement_timeoutglobal modéré protège contre les requêtes emballées ; la réponse à un faux positif est une surcharge cadrée, pas de le désactiver.
