instructure/canvas-lms · error · EmbedNotFoundError

Embed not found for resource type: #

Error message

Embed not found for resource type: #{embed[:resource_type]}, id: #{embed[:id]}, src: #{embed[:src]}

What it means

mark_embed_as_converted walks scan_progress.results[:resources] to decrement counts and drop the converted embed; if the resource/embed entry it expects is not present in the progress hash (the lookup branch fails), it raises EmbedNotFoundError with the type, id, and src. This is a bookkeeping failure during bulk conversion rather than initial validation.

Solutions

  1. Ensure only one conversion job runs per scan progress (idempotency guard / unique job lock)
  2. Re-run the scan then retry conversion with a fresh progress record
  3. Make mark_embed_as_converted tolerant: skip/no-op (with log) when the entry is already absent instead of raising
  4. Serialize scan and convert phases so a re-scan cannot reset results mid-conversion

Example fix

// before
raise EmbedNotFoundError, "Embed not found for resource type: ..."
// after
Rails.logger.warn("embed already removed from progress: #{embed[:resource_type]} #{embed[:id]}")
return # idempotent no-op on double conversion
Defensive patterns

Strategy: retry

Validate before calling

# before bulk conversion, ensure no other job holds the progress
progress = Progress.find(scan_id)
raise 'conversion already in progress' if progress.locked? # or use a unique-job adapter

Try / catch

begin
  perform_embed_list_conversion(...)
rescue YoutubeMigrationService::EmbedNotFoundError => e
  Rails.logger.warn("progress entry vanished (double conversion?): #{e.message}")
end

Prevention

When it happens

Trigger: perform_embed_list_conversion processing an embed whose entry was already removed by a prior conversion, results were reset mid-run by a concurrent re-scan, or the key/embed shape changed between scan and convert phases.

Common situations: Duplicate conversion jobs running concurrently on the same Progress row (double-decrement); re-scan kicked off while bulk convert is running; stale job retried after completion; results hash shape mismatch after code changes.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at app/services/youtube_migration_service.rb:717

        (embed[:content_id].to_s.presence || "") ==
          (resource_embed[:content_id].to_s.presence || "")
    end

    if found_embed
      was_already_converted = resource[:embeds][index][:converted] == true

      unless was_already_converted
        resource[:embeds][index][:converted] = true
        resource[:embeds][index][:converted_at] = Time.now.utc
        resource[:converted_count] = (resource[:converted_count] || 0) + 1
        scan_progress.results[:total_converted] = (scan_progress.results[:total_converted] || 0) + 1
        scan_progress.results[:total_count] = [scan_progress.results[:total_count] - 1, 0].max
      end

      scan_progress.results[:resources][key] = resource
      scan_progress.save!
    else
      raise EmbedNotFoundError, "Embed not found for resource type: #{embed[:resource_type]}, id: #{embed[:id]}, src: #{embed[:src]}"
    end
  end

  def process_new_quizzes_scan_update(scan_id, new_quizzes_scan_status:, new_quizzes_scan_results: {})
    progress = self.class.find_scan(course, scan_id)
    results = progress.results || {}
    results[:new_quizzes_scan_status] = new_quizzes_scan_status

    begin
      if new_quizzes_scan_status == "completed"
        scan_results = (new_quizzes_scan_results || {}).deep_symbolize_keys
        new_quizzes_resources = {}

        resources_array = scan_results[:resources] || []
        resources_array.each do |resource|
          key = YoutubeMigrationService.generate_resource_key(resource[:type], resource[:id])
          new_quizzes_resources[key] = resource
        end

View on GitHub (pinned to 1c9f0bb801)