instructure/canvas-lms · error · RuntimeError
Use Lti::ResourceLink#current_external_tool to lookup…
Error message
Use Lti::ResourceLink#current_external_tool to lookup associated tool
What it means
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.
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.
Example fix
// before tool = resource_link.context_external_tool // after tool = resource_link.current_external_tool(course)
Defensive patterns
Strategy: type-guard
Validate before calling
# ensure code paths use the safe accessor unless resource_link.respond_to?(:current_external_tool) raise 'Canvas version without Lti::ResourceLink#current_external_tool; upgrade required' end tool = resource_link.current_external_tool(context)
Type guard
def safe_external_tool(resource_link, context) return resource_link.current_external_tool(context) if resource_link.respond_to?(:current_external_tool) raise ArgumentError, 'use current_external_tool(context) for tool lookup; context_external_tool is unsupported' end
Try / catch
begin
tool = resource_link.current_external_tool(context)
rescue NoMethodError => e
raise "ResourceLink tool lookup unavailable (#{e.message}); verify Canvas/gem version"
end Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
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
- Unable to find external tool to import content.
- Access token expired
- Access token invalid - signature likely incorrect
- assignment_invalid
- Assignment not configured for external tool launches
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/629a45861d414cd1.
Report an issue: GitHub.
Appendix: source
Thrown at app/models/lti/resource_link.rb:73
super
end
def self.create_with(context, tool, custom_params = nil, url = nil, title = nil, lti_1_1_id: nil)
return if context.nil? || tool.nil?
context.lti_resource_links.create!(
custom: Lti::DeepLinkingUtil.validate_custom_params(custom_params),
context_external_tool: tool,
url:,
title:,
lti_1_1_id:
)
end
def context_external_tool
# Use 'current_external_tool' to lookup the tool in a way that is safe with
# tool reinstallation and content migrations
raise "Use Lti::ResourceLink#current_external_tool to lookup associated tool"
end
def current_external_tool(context)
Lti::ToolFinder.from_url(
original_context_external_tool.url || original_context_external_tool.domain,
context,
preferred_tool_id: original_context_external_tool.id,
only_1_3: true
)
end
def self.find_or_initialize_for_context_and_lookup_uuid(
context:,
lookup_uuid:,
custom: nil,
url: nil,
context_external_tool: nil,
context_external_tool_launch_url: nilView on GitHub (pinned to 1c9f0bb801)