instructure/canvas-lms · error · Pv4Timeout
failed to load page view history due to service timeout
Error message
failed to load page view history due to service timeout
What it means
Pv4Client#fetch rescues Net::ReadTimeout and re-raises it as Pv4Timeout with a user-facing message. It means the PV4 page-view service did not respond within the HTTP read timeout while loading page-view history.
Solutions
- Retry the request, possibly narrowing the date range (oldest/newest) to reduce response size
- Increase the PV4 client read/open timeout configuration if queries legitimately take longer
- Check PV4 service health/scaling and network path between services
- Surface a friendly 'history temporarily unavailable' message and allow the user to retry
Example fix
// before PageView.for_user(user, oldest: 2.years.ago) // after begin PageView.for_user(user, oldest: 2.years.ago) rescue Pv4Timeout PageView.for_user(user, oldest: 1.month.ago) end
Defensive patterns
Strategy: retry
Try / catch
begin views = PageView.for_user(user, oldest: range_start) rescue Pv4Timeout views = PageView.for_user(user, oldest: range_start + 6.months) rescue Pv4Timeout views = [] end
Prevention
- Keep queried time ranges small; paginate with bookmarks
- Set realistic read timeouts for the PV4 deployment
- Monitor PV4 service latency and scale proactively
- Fallback to a smaller window or a friendly retry message in the UI
When it happens
Trigger: Calling Pv4Client#fetch (via PageView.for_user) when the PV4 service is slow, overloaded, or the query is very large (long time range / high-volume user), exceeding the configured read timeout.
Common situations: PV4 service degradation or outage; querying history for a very active user over a long window; network latency between Canvas and PV4; timeout configured too aggressively for the deployment.
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
- could not retrieve configuration, the server response timed…
- Fetching data from #
- rate limit exceeded
- resource not found
- Unable to start import for external tool #
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/b7381a2cef97f1f9.
Report an issue: GitHub.
Appendix: source
Thrown at app/models/page_view/pv4_client.rb:99
elsif http_request.present?
"#{HostUrl.protocol}:#{http_request}"
elsif vhost.present?
"#{HostUrl.protocol}://#{vhost}"
end
pv["context_id"] = pv.delete("canvas_context_id")
pv["context_type"] = pv.delete("canvas_context_type")
pv["updated_at"] = pv["created_at"] = pv.delete("timestamp")
pv["user_agent"] = pv.delete("agent").presence
pv["account_id"] = pv.delete("root_account_id")
pv["remote_ip"] = pv.delete("client_ip")
pv["render_time"] = pv.delete("microseconds").to_f / 1_000_000
pv["http_method"].try(:downcase!)
pv["developer_key_id"] = pv.delete("developer_key_id")
PageView.from_attributes(pv)
end
rescue Net::ReadTimeout
raise Pv4Timeout, "failed to load page view history due to service timeout"
end
def for_user(user, oldest: nil, newest: nil)
bookmarker = Bookmarker.new(self)
BookmarkedCollection.build(bookmarker) do |pager|
bookmark = pager.current_bookmark
if bookmark
end_time, last_page_view_id = bookmark
newest = Time.zone.parse(end_time)
end
pager.replace(fetch(user,
start_time: oldest,
end_time: newest,
last_page_view_id:,
limit: pager.per_page))
pager.has_more! if pager.size >= pager.per_page
pager
endView on GitHub (pinned to 1c9f0bb801)