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

  1. Replace MediaObject.find_by(media_id: x) with MediaObject.by_media_id(x) (then narrow per context/attachment as needed)
  2. If filtering by more keys is needed, use by_media_id scope plus additional where clauses
  3. 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

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


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
  end

View on GitHub (pinned to 1c9f0bb801)