instructure/canvas-lms · error

Couldn't find QTI Migration Tool. See…

Error message

Couldn't find QTI Migration Tool. See https://github.com/instructure/QTIMigrationTool/wiki for installation instructions.

What it means

The qti_exporter plugin shells out to an external Python QTI Migration Tool binary to convert QTI packages. get_conversion_command raises this when the class variable @migration_executable was never located/initialized. It is a hard dependency failure: exports/conversions cannot proceed without the tool.

Solutions

  1. Install the QTI Migration Tool per https://github.com/instructure/QTIMigrationTool/wiki and make it executable
  2. Ensure the tool's directory is on PATH so the gem's executable lookup succeeds
  3. Verify in a console that QTI.migration_executable is set after boot
  4. For CI/dev-only environments that never export QTI, guard the export feature behind a feature flag or skip those specs

Example fix

// before (tool missing)
$ which migration_tool  # -> not found
// after
$ git clone https://github.com/instructure/QTIMigrationTool.git && export PATH=$PATH:/path/to/QTIMigrationTool
Defensive patterns

Strategy: validation

Validate before calling

raise 'QTI tool not installed' unless defined?(QTI) && QTI.migration_executable.present?

Try / catch

begin
  QTI.get_conversion_command(out_dir, manifest)
rescue RuntimeError => e
  raise unless e.message.include?('QTI Migration Tool')
  Rails.logger.error('Install QTIMigrationTool: see wiki')
  raise ExportSetupError
end

Prevention

When it happens

Trigger: Calling QTI.get_conversion_command (or any export flow that reaches it, e.g. course copy/QTI export) when QTI.migration_executable was never set — the tool isn't installed, isn't on PATH, or the lookup in the gem's init failed to find it.

Common situations: Fresh dev environments or Docker images without the QTIMigrationTool cloned/built; the tool not added to PATH; upgrading Canvas and skipping the setup doc at the wiki link in the message.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15). Data as JSON: /api/errors/a6527e59270f6670. Report an issue: GitHub.

Appendix: source

Thrown at gems/plugins/qti_exporter/lib/qti.rb:129

  end

  def self.convert_files(manifest_path)
    attachments = []
    doc = Nokogiri::XML(File.open(manifest_path))
    resource_nodes = doc.css("resource")
    doc.css("file").each do |file|
      # skip resource nodes, which are things like xml metadata and other sorts
      next if resource_nodes.any? { |node| node["href"] == file["href"] }

      # anything left is a file that needs to become an attachment on the context
      attachments << CGI.unescape(file["href"])
    end
    attachments
  end

  def self.get_conversion_command(out_dir, manifest_file, file_path_prepend = nil)
    if @migration_executable.nil?
      raise "Couldn't find QTI Migration Tool. See https://github.com/instructure/QTIMigrationTool/wiki for installation instructions."
    else
      prepend = file_path_prepend ? "--pathprepend=\"#{file_path_prepend}\" " : ""
      "\"#{@migration_executable}\" #{prepend}--ucvars --nogui --overwrite --cpout=#{Shellwords.escape(out_dir)} #{Shellwords.escape(manifest_file)} 2>&1"
    end
  end
end

View on GitHub (pinned to 1c9f0bb801)