{"record":{"id":"38876069fd63be97","repo":"instructure/canvas-lms","slug":"scan-not-found-for-id-scan-id","errorCode":null,"errorMessage":"Scan not found for id: #{scan_id}","messagePattern":"Scan not found for id: #(.+?)","errorType":"exception","errorClass":"EmbedNotFoundError","httpStatus":404,"severity":"error","filePath":"app/services/youtube_migration_service.rb","lineNumber":143,"sourceCode":"    else\n      resource_group_key || YoutubeMigrationService.generate_resource_key(resource_type, id)\n    end\n  end\n\n  def self.generate_resource_key(type, id)\n    \"#{type}|#{id}\"\n  end\n\n  attr_accessor :course\n\n  def initialize(course)\n    self.course = course\n  end\n\n  def validate_scan_exists!(scan_id)\n    YoutubeMigrationService.find_scan(course, scan_id)\n  rescue ActiveRecord::RecordNotFound\n    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","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/services/youtube_migration_service.rb#L125-L161","documentation":"validate_scan_exists! looks up the youtube_embed_scan Progress record for the course via YoutubeMigrationService.find_scan. If no Progress with that scan_id exists for the course, ActiveRecord::RecordNotFound is rescued and re-raised as EmbedNotFoundError. It guards the embed-conversion flow from operating on a missing/stale scan.","triggerScenarios":"Calling convert_embed (or validate_scan_exists!) with a scan_id that was never created, belongs to a different course, or whose Progress record was deleted/expired.","commonSituations":"Reusing a scan id from another course or shard; scan Progress purged between scan and convert phases; client passing a hard-coded or fabricated scan_id; job retry after the Progress row was removed.","solutions":["Run the scan (SCAN_TAG Progress) for the course first and use the id of the resulting Progress record","Verify the scan_id belongs to the same course whose YoutubeMigrationService instance you are using","Check Progress.where(tag: 'youtube_embed_scan', context: course) to list valid scan ids","If the scan is gone, re-scan and retry conversion with the new scan_id"],"exampleFix":"// before\nservice.convert_embed(stale_scan_id, embed)\n// after\nscan = Progress.where(tag: 'youtube_embed_scan', context: course).last\nraise 'no scan available; run the scan first' unless scan\nservice.convert_embed(scan.id, embed)","handlingStrategy":"try-catch","validationCode":"scan = Progress.where(tag: 'youtube_embed_scan', context: course).find_by(id: scan_id)\nraise 'scan_id does not belong to this course' unless scan","typeGuard":"def valid_scan?(course, scan_id)\n  scan_id.is_a?(Integer) && Progress.where(tag: 'youtube_embed_scan', context: course).exists?(id: scan_id)\nend","tryCatchPattern":"begin\n  service.convert_embed(scan_id, embed)\nrescue YoutubeMigrationService::EmbedNotFoundError => e\n  Rails.logger.warn(\"scan missing: #{e.message}; re-running scan\")\n  YoutubeMigrationService.run_scan(course)\nend","preventionTips":["Always obtain scan_id from the Progress record returned by the scan phase for the same course","Never hard-code scan ids across environments","Account for Progress row retention/cleanup between scan and convert"],"tags":["ruby","activerecord","resource-not-found","migration"],"backgroundTag":"record-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"}