instructure/canvas-lms · error · ResourceNotFoundError
Resource not found for type: #
Error message
Resource not found for type: #{resource_type}, id: #{resource_id} What it means
validate_resource_exists! looks up the actual record (e.g. WikiPage, Quizzes::Quiz, QuizQuestion, AssessmentQuestion, DiscussionTopic, Assignment, etc.) with .find. ActiveRecord::RecordNotFound is rescued and re-raised as ResourceNotFoundError naming the type and id, so conversion stops when the backing content no longer exists.
Solutions
- Verify the record still exists for that id in the same shard/course before converting; re-run the scan to refresh ids if content was recreated
- Skip this embed and continue converting the rest, logging the dangling reference
- If content was deleted intentionally, remove the embed from the content rather than converting
- Check that the resource_type matches the id's actual model (QuizQuestion id vs AssessmentQuestion id mix-ups)
Example fix
// before
service.convert_embed(scan_id, { resource_type: 'Quizzes::Quiz', id: deleted_quiz_id, ... })
// after
begin
service.convert_embed(scan_id, embed)
rescue YoutubeMigrationService::ResourceNotFoundError => e
Rails.logger.warn("skipping unconvertible embed: #{e.message}")
end Defensive patterns
Strategy: try-catch
Validate before calling
model = embed[:resource_type].safe_constantize raise 'record missing' unless model && embed[:resource_type] != 'CourseSyllabus' && model.where(id: embed[:id]).exists?
Try / catch
begin
service.convert_embed(scan_id, embed)
rescue YoutubeMigrationService::ResourceNotFoundError => e
Rails.logger.warn("dangling embed skipped: #{e.message}")
next # continue with remaining embeds
end Prevention
- Convert soon after scanning to minimize deletion windows
- Handle skips gracefully in bulk conversion instead of aborting
- Re-scan after content imports/deletes to refresh ids
When it happens
Trigger: convert_embed where resource_id references a deleted record, an id from another course/shard, or a type whose id semantics differ (e.g. passing a quiz question's assessment_question id).
Common situations: Content deleted between scan and convert (weeks can pass); restoring/importing courses that reassign ids; migrating data across environments; soft-deleted or unpublished records the scan once saw.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- Course not found
- Scan not found for id: #
- A student referenced a non-existent user #
- An institutional tag category did not pass validation
- Can't delete a non-existent observer for observer: #
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/6b3c7d810e060911.
Report an issue: GitHub.
Appendix: source
Thrown at app/services/youtube_migration_service.rb:215
course.discussion_topics.find(resource_id)
when "DiscussionEntry"
DiscussionEntry.find(resource_id)
when "CalendarEvent"
course.calendar_events.find(resource_id)
when "Quizzes::Quiz"
course.quizzes.find(resource_id)
when "Quizzes::QuizQuestion"
Quizzes::QuizQuestion.find(resource_id)
when "AssessmentQuestion"
AssessmentQuestion.find(resource_id)
when "CourseSyllabus", "Course"
# For syllabus, the resource_id is the course id
raise ResourceNotFoundError, "Course not found" unless course.id == resource_id
else
raise ResourceNotFoundError, "Cannot validate existence for resource type: #{resource_type}"
end
rescue ActiveRecord::RecordNotFound
raise ResourceNotFoundError, "Resource not found for type: #{resource_type}, id: #{resource_id}"
end
def convert_embed(scan_id, embed, user_uuid: nil)
validate_scan_exists!(scan_id)
validate_supported_resource!(embed[:resource_type])
resource_group_key = embed[:resource_group_key] || YoutubeMigrationService.generate_resource_key(embed[:resource_type], embed[:id])
validate_resource_group_key!(resource_group_key)
validate_embed_exists_in_scan!(scan_id, embed)
validate_resource_exists!(embed[:resource_type], embed[:id])
message = YoutubeMigrationService.generate_resource_key(embed[:resource_type], embed[:id])
# TODO: Something will listen on this creation
convert_progress = Progress.create!(tag: CONVERT_TAG, context: course, message:, results: { original_embed: embed })
job_priority = Account.site_admin.feature_enabled?(:youtube_migration_high_priority) ? Delayed::HIGH_PRIORITY : Delayed::LOW_PRIORITY
n_strand = "youtube_embed_convert_#{course.global_id}_#{resource_group_key}"
convert_progress.process_job(YoutubeMigrationService, :perform_conversion, { n_strand:, priority: job_priority }, course.id, scan_id, embed, user_uuid:)View on GitHub (pinned to 1c9f0bb801)