psycopg2.errors.QueryCanceled: ERROR: canceling statement due to statement timeout
ID: database/query-timeout
Version Compatibility
| Version | Status | Introduced | Deprecated | Notes |
|---|---|---|---|---|
| 16 | active | — | — | — |
Root Cause
A query exceeded the configured statement_timeout and was canceled by PostgreSQL. The query was running too long, typically due to missing indexes, full table scans on large tables, lock contention, or unoptimized queries. The timeout is a safety mechanism to prevent runaway queries.
genericWorkarounds
-
90% success Analyze and optimize the slow query using EXPLAIN ANALYZE
Run: EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT) <your_query>; Look for sequential scans on large tables, nested loops with high row counts, and sorts on unindexed columns. Add targeted indexes: CREATE INDEX CONCURRENTLY idx_name ON table(column); Rewrite the query to use index-friendly WHERE clauses.
-
85% success Set per-query or per-session statement_timeout for specific use cases
Instead of changing the global timeout, set it per transaction for known long-running operations: SET LOCAL statement_timeout = '120s'; <long_query>; COMMIT; This keeps the global safety net while allowing specific queries more time. For reporting queries, consider using a read replica with a higher timeout.
Dead Ends
Common approaches that don't work:
-
Setting statement_timeout to 0 (disabled) globally in production
80% fail
Disabling the timeout allows runaway queries to consume resources indefinitely, potentially blocking other queries, filling up connection slots, and causing cascading failures across the application.
-
Simply increasing statement_timeout without investigating query performance
70% fail
If a query takes 30 seconds and you increase the timeout to 60 seconds, it may work temporarily. But as data grows, the query will eventually exceed the new limit too. This does not fix the root cause and just delays the problem.