{"record":{"id":"d1d9cfefdff0e13c","repo":"instructure/canvas-lms","slug":"unable-to-find-external-tool-to-import-content","errorCode":null,"errorMessage":"Unable to find external tool to import content.","messagePattern":"Unable to find external tool to import content\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"app/models/lti/content_migration_service/importer.rb","lineNumber":102,"sourceCode":"      end\n\n      private\n\n      def start_import_post_body(content)\n        {\n          context_id: Lti::V1p1::Asset.opaque_identifier_for(@course),\n          data: content,\n          tool_consumer_instance_guid: @root_account.lti_guid,\n        }.merge(expanded_variables)\n      end\n\n      def load_tool!\n        return @tool if @tool\n\n        original_tool = ContextExternalTool.find(@original_tool_id)\n        @tool = Lti::ToolFinder.from_url(original_tool.domain, @course, preferred_tool_id: @original_tool_id).tap do |t|\n          unless t&.content_migration_configured?\n            raise \"Unable to find external tool to import content.\"\n          end\n        end\n      end\n\n      def import_start_url\n        @import_url ||= @tool.settings.dig(:content_migration, :import_start_url)\n      end\n\n      def import_format\n        @tool.settings.dig(:content_migration, :import_format)\n      end\n    end\n  end\nend\n","sourceCodeStart":84,"sourceCodeEnd":117,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/models/lti/content_migration_service/importer.rb#L84-L117","documentation":"Raised by Lti::ContentMigrationService::Importer#load_tool! when the original ContextExternalTool exists but Lti::ToolFinder.from_url cannot resolve a tool for the course whose content_migration is configured, or the resolved tool lacks content_migration_configured?. It means Canvas cannot find a valid external tool in the target course to send the imported content to.","triggerScenarios":"Calling send_imported_content with an original_tool_id whose tool (a) was deleted (ContextExternalTool.find raises RecordNotFound upstream or the domain lookup fails), (b) is not installed/available in the target course's account chain, or (c) is found but has no content_migration configuration (no import settings in its tool XML/settings).","commonSituations":"Importing a course copy into a different Canvas account/instance where the external tool was never installed; the tool was uninstalled or replaced between export and import (tool reinstallation changes IDs); tool configuration XML updated and the content_migration block removed; admin disabled the tool in the target course.","solutions":["Install/re-install the external tool in the target course's account (or course) so ToolFinder can resolve it by domain/url.","Verify the tool's configuration includes the content_migration settings (import_start_url) — re-add them in the tool XML or app settings.","Check the tool is available in the target course's context and not disabled at account/sub-account level.","Confirm @original_tool_id points to an existing ContextExternalTool on this Canvas instance (not a stale ID from another environment).","Use preferred_tool_id matching (reinstalled tools) or re-copy the course after the tool is properly configured."],"exampleFix":"# before: import into account lacking the tool\n# \"Unable to find external tool to import content.\"\n# after: install the tool in the destination account first, then re-run the import\ntool = account.context_external_tools.create!(name: 'Vendor Tool', domain: 'tool.example.com', settings: { content_migration: { import_start_url: 'https://tool.example.com/import' } })","handlingStrategy":"validation","validationCode":"# check before calling send_imported_content\noriginal_tool = ContextExternalTool.find_by(id: original_tool_id)\nresolved = original_tool && Lti::ToolFinder.from_url(original_tool.domain, course, preferred_tool_id: original_tool_id)\nunless resolved&.content_migration_configured?\n  raise \"Tool #{original_tool_id} is not installed/configured for content migration in #{course.name}; install it first.\"\nend","typeGuard":"def tool_ready_for_import?(course, original_tool_id)\n  original_tool = ContextExternalTool.find_by(id: original_tool_id)\n  return false unless original_tool\n  tool = Lti::ToolFinder.from_url(original_tool.domain, course, preferred_tool_id: original_tool_id)\n  !tool.nil? && tool.content_migration_configured?\nend","tryCatchPattern":"begin\n  importer.send_imported_content(course, migration, content)\nrescue RuntimeError => e\n  if e.message == 'Unable to find external tool to import content.'\n    # prompt admin to install the tool in the destination account, or skip this tool's content\n    flag_missing_tool(original_tool_id)\n  else\n    raise\n  end\nend","preventionTips":["Always install and configure the external tool in the destination account before importing a course copy.","Verify content_migration settings exist in the tool's configuration XML.","Check tool availability (not disabled) in the target course's context chain.","When migrating between environments, remap original_tool_ids to the tools installed in that environment."],"tags":["lti","external-tool","configuration","course-import","tool-lookup"],"backgroundTag":"entity-not-found","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"}