instructure/canvas-lms · error · RuntimeError
Do not look up MediaObjects by media_id - use the scope…
Error message
Do not look up MediaObjects by media_id - use the scope by_media_id instead to support migrated content.
What it means
MediaObject.find_by is overridden to reject lookups keyed only on media_id outside production, because media_id is not globally unique after content migrations — records can share a media_id across contexts. Callers must use the by_media_id scope which resolves the correct object per context.
Solutions
- Replace MediaObject.find_by(media_id: x) with MediaObject.by_media_id(x) (then narrow per context/attachment as needed)
- If filtering by more keys is needed, use by_media_id scope plus additional where clauses
- Update specs/console commands to the scope
Example fix
// before mo = MediaObject.find_by(media_id: media_id) // after mo = MediaObject.by_media_id(media_id).first
Defensive patterns
Strategy: type-guard
Validate before calling
mo = MediaObject.by_media_id(media_id).first # never find_by(media_id:)
Type guard
def safe_media_lookup(media_id, context) MediaObject.by_media_id(media_id).where(context_type: context.class.name, context_id: context.id).first end
Try / catch
begin
MediaObject.find_by(media_id: id)
rescue RuntimeError => e
raise unless e.message.include?('by_media_id')
MediaObject.by_media_id(id).first
end Prevention
- Grep the codebase for find_by(media_id: and replace with by_media_id scope
- Note the guard is skipped in production — migrate code before deploy
When it happens
Trigger: Calling MediaObject.find_by(media_id: id) or find_by(media_id:, ...) with other keys in a non-production Rails environment; specs or console code using the plain finder.
Common situations: Old code predating migrated-content support; grep-found snippets copied from older plugins; developers probing in rails console in dev/test.
Understand the failure class
Background: "is deprecated and will be removed" — deprecation warnings for old API names, keywords, and options, and how to migrate before the removal release — this error's family across 29 libraries.
Related errors
- An institutional tag category did not pass validation
- cannot change column: captions - locked by Master Course
- conversation_ids needs to be scoped to a user
- Course not found
- invalid media_object_id
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/318c36d4d96da7f3.
Report an issue: GitHub.
Appendix: source
Thrown at app/models/media_object.rb:80
after_create :retrieve_details_later
after_save :update_title_on_kaltura_later
serialize :data
attr_accessor :podcast_associated_asset, :current_attachment
def user_entered_title=(val)
@push_user_title = true
super
end
def update_title_on_kaltura_later
delay.update_title_on_kaltura if @push_user_title
@push_user_title = nil
end
def self.find_by(**kwargs)
if kwargs.key?(:media_id) && !Rails.env.production?
raise "Do not look up MediaObjects by media_id - use the scope by_media_id instead to support migrated content."
end
super
end
def context_root_account(user = nil)
# Granular Permissions
#
# The primary use case for this method is for accurately checking
# feature flag enablement, given a user and the calling context.
# We want to prefer finding the root_account through the context
# of the authorizing resource or fallback to the user's active
# pseudonym's residing account.
return context.account if context.is_a?(User)
# return nil and don't raise if receiver doesn't respond to :root_account
context.try(:root_account) || user&.account
endView on GitHub (pinned to 1c9f0bb801)