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
- Ensure the call happens within a request/context where Lti current_scope is set before invoking info_for_display
- Guard the call site: only call info_for_display if Lti::AssetProcessor.current_scope is present
- 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
- Only call info_for_display from request contexts that establish LTI current_scope
- Check current_scope presence before class-level helper calls
- Prefer explicit relation queries in jobs/console
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
- Peer reviews cannot be used with External Tool assignments
- Please don't turn off the default developer key
- Please never delete the default developer key
- Access token expired
- Access token invalid - signature likely incorrect
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)