{"record":{"id":"fa2e3e913b92527b","repo":"instructure/canvas-lms","slug":"element-not-found-at-path-path","errorCode":null,"errorMessage":"Element not found at path: #{@path}","messagePattern":"Element not found at path: #(.+?)","errorType":"exception","errorClass":"ElementNotFoundError","httpStatus":404,"severity":"error","filePath":"app/models/accessibility/content_loader.rb","lineNumber":57,"sourceCode":"    def content\n      if @path.present?\n        html, metadata = extract_element_from_content\n        { content: html, metadata: }\n      else\n        { content: full_document, metadata: {} }\n      end\n    end\n\n    def full_document\n      resource_html_content\n    end\n\n    def extract_element_from_content\n      html_content = resource_html_content\n\n      element = find_element_at_path(html_content, @path)\n\n      raise ElementNotFoundError, \"Element not found at path: #{@path}\" unless element\n\n      html = generate_preview_html(element)\n      metadata = extract_metadata(element)\n      [html, metadata]\n    end\n\n    private\n\n    def resource_html_content\n      # Check if resource implements the new AccessibilityCheckable interface\n      if @resource.respond_to?(:scannable_content)\n        # New path for resources using AccessibilityCheckable (e.g., SyllabusResource)\n        @resource.scannable_content\n      else\n        # Legacy path for non-migrated resources\n        case @resource\n        when Assignment\n          @resource.description","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/models/accessibility/content_loader.rb#L39-L75","documentation":"Accessibility::ContentLoader.extract_element_from_content locates a specific HTML element inside a resource's HTML content by traversing a path (e.g. element indexes). If find_element_at_path returns nil — the path points past the document tree or into a mismatched structure — ElementNotFoundError is raised so the accessibility checker can report the content as unloadable rather than crashing on a nil element.","triggerScenarios":"Requesting an accessibility preview/check of course content (assignment, page, etc.) with a path whose indexes exceed the actual DOM depth, or where the content was edited/reordered after the path was computed.","commonSituations":"Stale element paths cached before the content was edited; content without the expected structure (empty body, stripped HTML); concurrent edits changing sibling counts; tooling generating paths against a different content version.","solutions":["Re-fetch the content and recompute the element path before loading","Validate the path length against the document depth (or catch ElementNotFoundError and return a 'content changed' response)","Ensure upstream tools re-enumerate elements rather than persisting absolute paths"],"exampleFix":"// before\nloader = Accessibility::ContentLoader.new(resource, path: \"0/3/1\")\nloader.extract_element_from_content # raises if path stale\n// after\nbegin\n  loader.extract_element_from_content\nrescue Accessibility::ContentLoader::ElementNotFoundError\n  path = recompute_path(resource)\n  loader = Accessibility::ContentLoader.new(resource, path: path)\n  loader.extract_element_from_content\nend","handlingStrategy":"try-catch","validationCode":"def path_within_depth?(html, path)\n  depth = Nokogiri::HTML(html).traverse.size\n  path.split(\"/\").map(&:to_i).all? { |i| i >= 0 } && path.split(\"/\").length <= depth\nend","typeGuard":null,"tryCatchPattern":"begin\n  html, metadata = loader.extract_element_from_content\nrescue Accessibility::ContentLoader::ElementNotFoundError\n  Rails.logger.warn(\"stale accessibility path: #{loader.path}\")\n  retry_with_recomputed_path(loader)\nend","preventionTips":["Do not persist absolute element paths across content edits — recompute on demand","Validate path indexes against current content before loading","Handle content-change races by re-enumerating elements after edits"],"tags":["accessibility","dom-path","content","not-found"],"backgroundTag":"resource-not-found","analyzedSha":"1c9f0bb8013ed69c4f2efe11fd483025469b7e6c","analyzedAt":"2026-09-15T20:33:18.891Z","contentChangedAt":"2026-09-15T20:33:18.891Z","schemaVersion":2},"datasetVersion":"2026-09-23T02:17:17.105Z"}