{"record":{"id":"cd04b34cd28833b7","repo":"instructure/canvas-lms","slug":"must-be-used-with-a-scope","errorCode":null,"errorMessage":"Must be used with a scope","messagePattern":"Must be used with a scope","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"app/models/lti/asset_processor.rb","lineNumber":88,"sourceCode":"  def icon_url\n    if icon.is_a?(Hash) && icon[\"url\"].is_a?(String)\n      icon[\"url\"].presence\n    end\n  end\n\n  def icon_or_tool_icon_url\n    icon_url || context_external_tool.extension_setting(placement, :icon_url)\n  end\n\n  def tool_placement_label\n    context_external_tool.label_for(placement, I18n.locale)\n  end\n\n  # Result structure should match with ExistingAttachedAssetProcessor in UI\n  # See also fields in app/graphql/types/lti_asset_processor_type.rb which are used\n  # in Speedgrader 2\n  def self.info_for_display\n    raise ArgumentError, \"Must be used with a scope\" unless current_scope\n\n    active.preload(:context_external_tool).map do |ap|\n      {\n        id: ap.id,\n        title: ap.title,\n        text: ap.text,\n        tool_id: ap.context_external_tool_id,\n        tool_name: ap.context_external_tool.name,\n        tool_placement_label: ap.tool_placement_label,\n        icon_or_tool_icon_url: ap.icon_or_tool_icon_url,\n        iframe: ap.iframe,\n        window: ap.window,\n      }.compact\n    end\n  end\n\n  def report_custom_variables\n    (custom || {}).merge(report&.dig(\"custom\") || {})","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/models/lti/asset_processor.rb#L70-L106","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"// before\nLti::AssetProcessor.info_for_display\n// after\nif Lti::AssetProcessor.current_scope\n  Lti::AssetProcessor.info_for_display\nelse\n  Lti::AssetProcessor.active.preload(:context_external_tool).map { |ap| ... }\nend","handlingStrategy":"type-guard","validationCode":"raise \"no current scope\" unless Lti::AssetProcessor.current_scope","typeGuard":"def info_available? = Lti::AssetProcessor.current_scope.present?","tryCatchPattern":"begin\n  Lti::AssetProcessor.info_for_display\nrescue ArgumentError => e\n  Rails.logger.warn(\"info_for_display without scope: #{e.message}\")\n  []\nend","preventionTips":["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"],"tags":["lti","rails","scope"],"backgroundTag":"missing-required-argument","analyzedSha":"1c9f0bb8013ed69c4f2efe11fd483025469b7e6c","analyzedAt":"2026-09-15T20:33:18.891Z","contentChangedAt":"2026-09-15T20:33:18.891Z","schemaVersion":2},"datasetVersion":"2026-09-23T02:17:17.105Z"}