{"record":{"id":"9ca7d0adedad3175","repo":"instructure/canvas-lms","slug":"embed-not-found-for-resource-type-embed-resource-type-id","errorCode":null,"errorMessage":"Embed not found for resource type: #{embed[:resource_type]}, id: #{embed[:id]}, src: #{embed[:src]}","messagePattern":"Embed not found for resource type: #(.+?), id: #(.+?), src: #(.+?)","errorType":"exception","errorClass":"EmbedNotFoundError","httpStatus":404,"severity":"error","filePath":"app/services/youtube_migration_service.rb","lineNumber":717,"sourceCode":"        (embed[:content_id].to_s.presence || \"\") ==\n          (resource_embed[:content_id].to_s.presence || \"\")\n    end\n\n    if found_embed\n      was_already_converted = resource[:embeds][index][:converted] == true\n\n      unless was_already_converted\n        resource[:embeds][index][:converted] = true\n        resource[:embeds][index][:converted_at] = Time.now.utc\n        resource[:converted_count] = (resource[:converted_count] || 0) + 1\n        scan_progress.results[:total_converted] = (scan_progress.results[:total_converted] || 0) + 1\n        scan_progress.results[:total_count] = [scan_progress.results[:total_count] - 1, 0].max\n      end\n\n      scan_progress.results[:resources][key] = resource\n      scan_progress.save!\n    else\n      raise EmbedNotFoundError, \"Embed not found for resource type: #{embed[:resource_type]}, id: #{embed[:id]}, src: #{embed[:src]}\"\n    end\n  end\n\n  def process_new_quizzes_scan_update(scan_id, new_quizzes_scan_status:, new_quizzes_scan_results: {})\n    progress = self.class.find_scan(course, scan_id)\n    results = progress.results || {}\n    results[:new_quizzes_scan_status] = new_quizzes_scan_status\n\n    begin\n      if new_quizzes_scan_status == \"completed\"\n        scan_results = (new_quizzes_scan_results || {}).deep_symbolize_keys\n        new_quizzes_resources = {}\n\n        resources_array = scan_results[:resources] || []\n        resources_array.each do |resource|\n          key = YoutubeMigrationService.generate_resource_key(resource[:type], resource[:id])\n          new_quizzes_resources[key] = resource\n        end","sourceCodeStart":699,"sourceCodeEnd":735,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/services/youtube_migration_service.rb#L699-L735","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure only one conversion job runs per scan progress (idempotency guard / unique job lock)","Re-run the scan then retry conversion with a fresh progress record","Make mark_embed_as_converted tolerant: skip/no-op (with log) when the entry is already absent instead of raising","Serialize scan and convert phases so a re-scan cannot reset results mid-conversion"],"exampleFix":"// before\nraise EmbedNotFoundError, \"Embed not found for resource type: ...\"\n// after\nRails.logger.warn(\"embed already removed from progress: #{embed[:resource_type]} #{embed[:id]}\")\nreturn # idempotent no-op on double conversion","handlingStrategy":"retry","validationCode":"# before bulk conversion, ensure no other job holds the progress\nprogress = Progress.find(scan_id)\nraise 'conversion already in progress' if progress.locked? # or use a unique-job adapter","typeGuard":null,"tryCatchPattern":"begin\n  perform_embed_list_conversion(...)\nrescue YoutubeMigrationService::EmbedNotFoundError => e\n  Rails.logger.warn(\"progress entry vanished (double conversion?): #{e.message}\")\nend","preventionTips":["Guard bulk conversion with unique-job/locking so it can't double-run","Don't trigger a re-scan while conversion is in flight","Make mark_embed_as_converted idempotent for already-removed entries"],"tags":["ruby","concurrency","migration","job-retry"],"backgroundTag":"invalid-state-transition","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"}