{"record":{"id":"629a45861d414cd1","repo":"instructure/canvas-lms","slug":"use-lti-resourcelink-current-external-tool-to-lookup","errorCode":null,"errorMessage":"Use Lti::ResourceLink#current_external_tool to lookup associated tool","messagePattern":"Use Lti::ResourceLink#current_external_tool to lookup associated tool","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"app/models/lti/resource_link.rb","lineNumber":73,"sourceCode":"    super\n  end\n\n  def self.create_with(context, tool, custom_params = nil, url = nil, title = nil, lti_1_1_id: nil)\n    return if context.nil? || tool.nil?\n\n    context.lti_resource_links.create!(\n      custom: Lti::DeepLinkingUtil.validate_custom_params(custom_params),\n      context_external_tool: tool,\n      url:,\n      title:,\n      lti_1_1_id:\n    )\n  end\n\n  def context_external_tool\n    # Use 'current_external_tool' to lookup the tool in a way that is safe with\n    # tool reinstallation and content migrations\n    raise \"Use Lti::ResourceLink#current_external_tool to lookup associated tool\"\n  end\n\n  def current_external_tool(context)\n    Lti::ToolFinder.from_url(\n      original_context_external_tool.url || original_context_external_tool.domain,\n      context,\n      preferred_tool_id: original_context_external_tool.id,\n      only_1_3: true\n    )\n  end\n\n  def self.find_or_initialize_for_context_and_lookup_uuid(\n    context:,\n    lookup_uuid:,\n    custom: nil,\n    url: nil,\n    context_external_tool: nil,\n    context_external_tool_launch_url: nil","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/models/lti/resource_link.rb#L55-L91","documentation":"Lti::ResourceLink#context_external_tool is deliberately unimplemented: it always raises to force callers onto current_external_tool(context) instead. The legacy lookup is unsafe because tool reinstallation and content migrations can change tool IDs/domains, so a context-less, cached lookup can return the wrong (stale) tool. This is a developer-guard error, not a runtime failure of the lookup itself.","triggerScenarios":"Any code calling resource_link.context_external_tool — e.g. plugin/custom code copied from pre-current_external_tool examples, or code that calls a method which internally uses the deprecated accessor. It raises unconditionally on every call.","commonSituations":"Upgrading custom LTI integrations after Canvas refactored ResourceLink tool lookup; copying sample code from old documentation; gems/plugins updated to newer Canvas where the accessor became a hard error; developers assuming context_external_tool is a plain association reader.","solutions":["Replace the call with resource_link.current_external_tool(context), passing the appropriate context (course, account, etc.).","Audit for other deprecated tool-lookup paths (e.g. accessing original_context_external_tool directly for runtime decisions) and route them through current_external_tool.","If you need the raw original tool record for non-runtime purposes, use original_context_external_tool explicitly and knowingly.","Update gems/plugins that call the old accessor to versions compatible with current_external_tool."],"exampleFix":"// before\ntool = resource_link.context_external_tool\n// after\ntool = resource_link.current_external_tool(course)","handlingStrategy":"type-guard","validationCode":"# ensure code paths use the safe accessor\nunless resource_link.respond_to?(:current_external_tool)\n  raise 'Canvas version without Lti::ResourceLink#current_external_tool; upgrade required'\nend\ntool = resource_link.current_external_tool(context)","typeGuard":"def safe_external_tool(resource_link, context)\n  return resource_link.current_external_tool(context) if resource_link.respond_to?(:current_external_tool)\n  raise ArgumentError, 'use current_external_tool(context) for tool lookup; context_external_tool is unsupported'\nend","tryCatchPattern":"begin\n  tool = resource_link.current_external_tool(context)\nrescue NoMethodError => e\n  raise \"ResourceLink tool lookup unavailable (#{e.message}); verify Canvas/gem version\"\nend","preventionTips":["Never call resource_link.context_external_tool; grep codebases/plugins for it during Canvas upgrades.","Always pass the runtime context (course/account) to current_external_tool so lookup survives reinstallations and migrations.","Update vendored plugins and snippets copied from old documentation.","Add a lint/custom cop flagging calls to context_external_tool."],"tags":["lti","deprecated-api","resource-link","tool-lookup","developer-guard"],"backgroundTag":"deprecated-api-usage","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"}