instructure/canvas-lms · error · GraphQLPostgresTimeout::Error
operation timed out
Error message
operation timed out
What it means
Canvas wraps GraphQL query execution so that when PostgreSQL kills a statement for exceeding statement_timeout (PG::QueryCanceled, wrapped in ActiveRecord::StatementInvalid), it logs the query and re-raises as GraphQLPostgresTimeout::Error 'operation timed out' instead of an opaque DB error.
Solutions
- Reduce query scope: request fewer/smaller fields and use smaller page sizes with pagination.
- Increase postgres statement_timeout or the GraphQL-specific timeout setting if the query is legitimately needed.
- Optimize the underlying query/indexes if the timeout is consistently hit.
Example fix
// before
{allCourses { nodes { enrollments { nodes { submissions { nodes { comments { nodes { body } } } } } } } }}
// after
{allCourses(first: 10) { nodes { enrollments(first: 10) { nodes { _id } } } }} Defensive patterns
Strategy: try-catch
Try / catch
try { const data = await graphQL(query, vars) } catch (e) { if (e.originalError?.message === 'operation timed out') { /* reduce query scope and paginate */ } else throw e } Prevention
- Paginate with first/after instead of unbounded lists
- Request only needed fields
- Watch statement_timeout settings when querying large datasets
- Add indexes for filters used by heavy GraphQL queries
When it happens
Trigger: Running a GraphQL query whose SQL exceeds the postgres statement_timeout — e.g. huge user/collection queries, unbounded pagination, or expensive enrollment/gradebook lookups under load.
Common situations: Development environments with small timeouts querying large production datasets; queries requesting huge page sizes; missing indexes or pathological filters causing long scans.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- operation timed out
- and cannot be used together
- and cannot be used together
- A course with that id does not exist
- A maximum of 50 assessees can be provided at once
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/a5328c7539958d28.
Report an issue: GitHub.
Appendix: source
Thrown at app/graphql/graphql_postgres_timeout.rb:40
class << self
attr_accessor :do_not_wrap
end
TIMEOUT = 60_000
def self.wrap(query)
if do_not_wrap
yield
else
ActiveRecord::Base.transaction do
ActiveRecord::Base.connection.execute "SET statement_timeout = #{TIMEOUT}"
yield
rescue ActiveRecord::StatementInvalid => e
if e.cause.is_a?(PG::QueryCanceled)
Rails.logger.warn do
"GraphQL Operation failed due to postgres statement_timeout:\n#{query.query_string}"
end
raise GraphQLPostgresTimeout::Error, "operation timed out"
end
raise
end
end
end
Error = Class.new(StandardError)
end
View on GitHub (pinned to 1c9f0bb801)