{"record":{"id":"5bf3f57dade96427","repo":"instructure/canvas-lms","slug":"course-not-found-youtube-migration-service","errorCode":null,"errorMessage":"Course not found","messagePattern":"Course not found","errorType":"exception","errorClass":"ResourceNotFoundError","httpStatus":404,"severity":"error","filePath":"app/services/youtube_migration_service.rb","lineNumber":210,"sourceCode":"    when \"WikiPage\"\n      course.wiki_pages.find(resource_id)\n    when \"Assignment\"\n      course.assignments.find(resource_id)\n    when \"DiscussionTopic\", \"Announcement\"\n      course.discussion_topics.find(resource_id)\n    when \"DiscussionEntry\"\n      DiscussionEntry.find(resource_id)\n    when \"CalendarEvent\"\n      course.calendar_events.find(resource_id)\n    when \"Quizzes::Quiz\"\n      course.quizzes.find(resource_id)\n    when \"Quizzes::QuizQuestion\"\n      Quizzes::QuizQuestion.find(resource_id)\n    when \"AssessmentQuestion\"\n      AssessmentQuestion.find(resource_id)\n    when \"CourseSyllabus\", \"Course\"\n      # For syllabus, the resource_id is the course id\n      raise ResourceNotFoundError, \"Course not found\" unless course.id == resource_id\n    else\n      raise ResourceNotFoundError, \"Cannot validate existence for resource type: #{resource_type}\"\n    end\n  rescue ActiveRecord::RecordNotFound\n    raise ResourceNotFoundError, \"Resource not found for type: #{resource_type}, id: #{resource_id}\"\n  end\n\n  def convert_embed(scan_id, embed, user_uuid: nil)\n    validate_scan_exists!(scan_id)\n    validate_supported_resource!(embed[:resource_type])\n\n    resource_group_key = embed[:resource_group_key] || YoutubeMigrationService.generate_resource_key(embed[:resource_type], embed[:id])\n    validate_resource_group_key!(resource_group_key)\n    validate_embed_exists_in_scan!(scan_id, embed)\n    validate_resource_exists!(embed[:resource_type], embed[:id])\n\n    message = YoutubeMigrationService.generate_resource_key(embed[:resource_type], embed[:id])\n    # TODO: Something will listen on this creation","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/services/youtube_migration_service.rb#L192-L228","documentation":"For resource types 'CourseSyllabus' or 'Course', validate_resource_exists! treats resource_id as a course id and requires it to equal the course the service was constructed with. If they differ, ResourceNotFoundError 'Course not found' is raised — cross-course embeds cannot be validated/converted.","triggerScenarios":"convert_embed on a syllabus/course embed whose resource_id points to a different course than YoutubeMigrationService.new(course) was initialized with.","commonSituations":"Copying syllabus content between courses; migrating a course and reusing old course ids; shard/shard-confusion where the id collides but belongs to another course; hard-coded ids from a previous environment.","solutions":["Pass the correct course when instantiating the service so course.id matches the embed's resource_id","Use the current course's id as resource_id for CourseSyllabus/Course embeds","Skip/re-route cross-course embeds to a service instance built for the owning course","Re-run the scan for the correct course so keys reference its id"],"exampleFix":"// before\nservice = YoutubeMigrationService.new(new_course)\nservice.convert_embed(scan_id, { resource_type: 'CourseSyllabus', id: old_course.id, ... })\n// after\nservice = YoutubeMigrationService.new(Course.find(resource_id))\nservice.convert_embed(scan_id, embed) # course.id == resource_id now","handlingStrategy":"try-catch","validationCode":"if %w[CourseSyllabus Course].include?(embed[:resource_type]) && embed[:id] != course.id\n  raise 'CourseSyllabus/Course embed belongs to a different course'\nend","typeGuard":null,"tryCatchPattern":"begin\n  service.convert_embed(scan_id, embed)\nrescue YoutubeMigrationService::ResourceNotFoundError => e\n  Rails.logger.warn(\"cross-course embed skipped: #{e.message}\")\nend","preventionTips":["Instantiate the service with the course that owns the embed","Never copy syllabus embed resource ids between courses","Re-scan per course rather than reusing ids across courses"],"tags":["ruby","activerecord","course-syllabus","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"}