instructure/canvas-lms · error · Pv4NotFound

resource not found

Error message

resource not found

What it means

Pv4Client#fetch raises Pv4NotFound when the PV4 (page views v4) service responds with HTTP 404. It means the requested page-view history resource does not exist on the remote service, e.g. the user has no page-view record set there or the request path/parameters are wrong. This converts a remote HTTP status into a typed Canvas error so callers (via PageView.for_user) can handle it.

Solutions

  1. Verify the user actually has page-view data in PV4 (query the service directly) before expecting results
  2. Check Pv4Client configuration (PV4 host/URL settings) points at the correct service
  3. Confirm the request parameters (user id, oldest/newest) are correct
  4. Handle Pv4NotFound gracefully in the UI (show empty history instead of a hard failure)

Example fix

// before
PageView.for_user(user)
// after
begin
  PageView.for_user(user)
rescue Pv4NotFound
  []
end
Defensive patterns

Strategy: try-catch

Validate before calling

return [] unless PageView.respond_to?(:for_user) # plus confirm PV4 feature enabled for account
# check PV4 config is present before calling
raise ArgumentError, "PV4 not configured" unless Pv4Client.new.send(:connection_present?) rescue nil

Type guard

def pv4_likely_has_data?(user)
  user.present? && user.shard.respond_to?(:page_views_enabled?)
end

Try / catch

begin
  views = PageView.for_user(user)
rescue Pv4NotFound
  views = []
end

Prevention

When it happens

Trigger: Calling PageView.for_user (which calls Pv4Client#fetch) when the PV4 service has no data for the user (404), the user id/timespan query matches nothing, or the PV4 endpoint URL/prefix is misconfigured.

Common situations: PV4 not deployed for the user's shard so no records exist; querying history for a brand-new user; environment misconfiguration of the PV4 service host; requests using stale bookmarks pointing at removed data.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15). Data as JSON: /api/errors/dd8238bc3d1c6eb8. Report an issue: GitHub.

Appendix: source

Thrown at app/models/page_view/pv4_client.rb:62

      start_time ||= Time.at(0).utc

      params = "start_time=#{start_time.utc.iso8601(PRECISION)}"
      params << "&end_time=#{end_time.utc.iso8601(PRECISION)}"
      params << "&#{cached_root_account_uuids_for(user:)}"
      params << "&last_page_view_id=#{last_page_view_id}" if last_page_view_id
      params << "&limit=#{limit}" if limit
      response = CanvasHttp.get(
        @uri.merge("users/#{user.global_id}/page_views?#{params}").to_s,
        request_headers
      )

      case response.code.to_i
      when 400
        raise Pv4BadRequest, "invalid request"
      when 401
        raise Pv4Unauthorized, "unauthorized request"
      when 404
        raise Pv4NotFound, "resource not found"
      when 429
        raise Pv4TooManyRequests, "rate limit exceeded"
      end

      json =
        begin
          response.body.empty? ? {} : JSON.parse(response.body)
        rescue JSON::ParserError
          {}
        end
      raise Pv4EmptyResponse, "the response is empty or does not contain expected keys" unless json["page_views"]

      json["page_views"].map! do |pv|
        pv["session_id"] = pv.delete("sessionid")
        vhost = pv.delete("vhost")
        http_request = pv.delete("http_request")
        pv["url"] = if vhost.present? && http_request.present?
                      "#{HostUrl.protocol}://#{vhost}#{http_request}"

View on GitHub (pinned to 1c9f0bb801)