instructure/canvas-lms · error · ArgumentError

Must be used with a scope

Error message

Must be used with a scope

What it means

Lti::AssetProcessor.info_for_display is a class-level helper that builds a hash per active asset processor for UI consumption (Speedgrader 2 / GraphQL type parity). It relies on current_scope being set (a scoped relation), because it calls active.preload(:context_external_tool) on the class. Without a scope the method cannot safely build the relation, so it raises ArgumentError.

Solutions

  1. Ensure the call happens within a request/context where Lti current_scope is set before invoking info_for_display
  2. Guard the call site: only call info_for_display if Lti::AssetProcessor.current_scope is present
  3. If querying outside a scoped context, build the query explicitly (e.g. where(...).active.preload(:context_external_tool)) instead of using info_for_display

Example fix

// before
Lti::AssetProcessor.info_for_display
// after
if Lti::AssetProcessor.current_scope
  Lti::AssetProcessor.info_for_display
else
  Lti::AssetProcessor.active.preload(:context_external_tool).map { |ap| ... }
end
Defensive patterns

Strategy: type-guard

Validate before calling

raise "no current scope" unless Lti::AssetProcessor.current_scope

Type guard

def info_available? = Lti::AssetProcessor.current_scope.present?

Try / catch

begin
  Lti::AssetProcessor.info_for_display
rescue ArgumentError => e
  Rails.logger.warn("info_for_display without scope: #{e.message}")
  []
end

Prevention

When it happens

Trigger: Calling Lti::AssetProcessor.info_for_display when no current_scope is set — e.g. invoking the class method directly outside a relation/context that establishes current_scope (typically set by LTI scopes in controllers).

Common situations: Calling info_for_display from a console, background job, or new code path that bypasses the controller code which normally establishes the LTI current scope; refactors that moved the call out of the original request context.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15). Data as JSON: /api/errors/cd04b34cd28833b7. Report an issue: GitHub.

Appendix: source

Thrown at app/models/lti/asset_processor.rb:88

  def icon_url
    if icon.is_a?(Hash) && icon["url"].is_a?(String)
      icon["url"].presence
    end
  end

  def icon_or_tool_icon_url
    icon_url || context_external_tool.extension_setting(placement, :icon_url)
  end

  def tool_placement_label
    context_external_tool.label_for(placement, I18n.locale)
  end

  # Result structure should match with ExistingAttachedAssetProcessor in UI
  # See also fields in app/graphql/types/lti_asset_processor_type.rb which are used
  # in Speedgrader 2
  def self.info_for_display
    raise ArgumentError, "Must be used with a scope" unless current_scope

    active.preload(:context_external_tool).map do |ap|
      {
        id: ap.id,
        title: ap.title,
        text: ap.text,
        tool_id: ap.context_external_tool_id,
        tool_name: ap.context_external_tool.name,
        tool_placement_label: ap.tool_placement_label,
        icon_or_tool_icon_url: ap.icon_or_tool_icon_url,
        iframe: ap.iframe,
        window: ap.window,
      }.compact
    end
  end

  def report_custom_variables
    (custom || {}).merge(report&.dig("custom") || {})

View on GitHub (pinned to 1c9f0bb801)