{"record":{"id":"ebd9baeeb95e7059","repo":"instructure/canvas-lms","slug":"embed-not-found-in-scan-for-resource-resource-group-key","errorCode":null,"errorMessage":"Embed not found in scan for resource: #{resource_group_key}","messagePattern":"Embed not found in scan for resource: #(.+?)","errorType":"exception","errorClass":"EmbedNotFoundError","httpStatus":404,"severity":"error","filePath":"app/services/youtube_migration_service.rb","lineNumber":161,"sourceCode":"    raise EmbedNotFoundError, \"Scan not found for id: #{scan_id}\"\n  end\n\n  def validate_embed_exists_in_scan!(scan_id, embed)\n    scan = YoutubeMigrationService.find_scan(course, scan_id)\n    resource_group_key = resource_group_key_for(embed)\n\n    return if scan.results.blank? || scan.results[:resources].blank?\n\n    resource = scan.results[:resources][resource_group_key]\n    raise EmbedNotFoundError, \"Resource not found in scan for key: #{resource_group_key}\" if resource.blank?\n\n    embed_exists = resource[:embeds].any? do |scan_embed|\n      scan_embed[:src] == embed[:src] &&\n        scan_embed[:field].to_s == embed[:field].to_s &&\n        scan_embed[:resource_type] == embed[:resource_type]\n    end\n\n    raise EmbedNotFoundError, \"Embed not found in scan for resource: #{resource_group_key}\" unless embed_exists\n  end\n\n  def prepare_new_quiz_resource_type(resource_type)\n    case resource_type\n    when /QuizzesNext::Quiz/\n      \"QuizzesNext::Quiz\"\n    when /QuizzesNext::Bank/\n      \"QuizzesNext::Bank\"\n    else\n      resource_type\n    end\n  end\n\n  def validate_supported_resource!(resource_type)\n    supported = SUPPORTED_RESOURCES.include?(resource_type) || NEW_QUIZZES_RESOURCES.include?(resource_type)\n    raise UnsupportedResourceTypeError, \"Unsupported resource type: #{resource_type}\" unless supported\n  end\n","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/services/youtube_migration_service.rb#L143-L179","documentation":"The resource exists in scan results but no scanned embed matches the given embed on all of src, field, and resource_type. EmbedNotFoundError is raised, meaning this particular embed (URL + RCE field + type combination) was not captured for that resource during the scan.","triggerScenarios":"convert_embed called with an embed whose src URL differs from the scanned one (e.g. normalized/rewritten youtu.be vs youtube.com), whose field name differs in type/string form handling beyond .to_s, or which was edited after the scan.","commonSituations":"Video URL edited between scan and convert; embed moved to a different field; hand-crafted embed hash with mismatched casing or extra parameters in src; scan performed before an LTI/Studio rewrite changed src values.","solutions":["Re-run the scan after content edits so the embed snapshot is current","Compare the embed's src/field/resource_type against scan.results[:resources][key][:embeds] entries","Normalize the src (same format the scanner records, e.g. canonical YouTube URL) before calling convert_embed","Ensure field is passed consistently (symbol vs string is handled by .to_s, but the name itself must match)"],"exampleFix":"// before\nconvert_embed(scan_id, { resource_type: 'WikiPage', id: id, src: edited_url, field: :body })\n// after\nscan = YoutubeMigrationService.find_scan(course, scan_id)\nrecorded = scan.dig(:results, :resources, \"WikiPage|#{id}\".to_sym, :embeds)\nmatch = recorded&.find { |e| e[:src] == canonical_youtube_url(edited_url) }\nraise 'embed not in latest scan; re-scan' unless match\nconvert_embed(scan_id, embed)","handlingStrategy":"validation","validationCode":"scan = YoutubeMigrationService.find_scan(course, scan_id)\nkey = \"#{embed[:resource_type]}|#{embed[:id]}\"\nembeds = scan.results.dig(:resources, key.to_sym, :embeds) || []\nraise 'embed not captured in scan' unless embeds.any? { |e| e[:src] == embed[:src] && e[:field].to_s == embed[:field].to_s }","typeGuard":null,"tryCatchPattern":"begin\n  service.convert_embed(scan_id, embed)\nrescue YoutubeMigrationService::EmbedNotFoundError => e\n  Rails.logger.warn(\"#{e.message}; re-scanning\")\n  YoutubeMigrationService.run_scan(course)\nend","preventionTips":["Keep src in the same canonical form the scanner records","Don't edit embed URLs/fields between scan and convert","Diff current content embeds against the scan snapshot before converting"],"tags":["ruby","migration","embed-not-found","scan"],"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"}