{"record":{"id":"0603b7bf226b0c09","repo":"instructure/canvas-lms","slug":"can-t-export-qti-without-the-python-converter-tool-installed","errorCode":null,"errorMessage":"Can't export QTI without the python converter tool installed.","messagePattern":"Can't export QTI without the python converter tool installed\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gems/plugins/qti_exporter/lib/canvas/migration/worker/qti_worker.rb","lineNumber":31,"sourceCode":"# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR\n# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more\n# details.\n#\n# You should have received a copy of the GNU Affero General Public License along\n# with this program. If not, see <http://www.gnu.org/licenses/>.\n\nmodule Canvas::Migration\n  module Worker\n    class QtiWorker < Base\n      def perform\n        cm = ContentMigration.where(id: migration_id).first\n        begin\n          cm.reset_job_progress\n          cm.job_progress.start\n          cm.update_conversion_progress(1)\n          plugin = Canvas::Plugin.find(:qti_converter)\n          unless plugin && plugin.settings[:enabled]\n            raise \"Can't export QTI without the python converter tool installed.\"\n          end\n\n          settings = cm.migration_settings.clone\n          settings[:content_migration_id] = migration_id\n          settings[:user_id] = cm.user_id\n          settings[:content_migration] = cm\n\n          if cm.attachment\n            settings[:attachment_id] = cm.attachment.id\n          elsif settings[:file_url]\n            att = Canvas::Migration::Worker.download_attachment(cm, settings[:file_url])\n            settings[:attachment_id] = att.id\n          elsif !settings[:no_archive_file]\n            raise Canvas::Migration::Error, I18n.t(:no_migration_file, \"File required for content migration.\")\n          end\n\n          converter = Qti::Converter.new(settings)\n          assessments = converter.export","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/gems/plugins/qti_exporter/lib/canvas/migration/worker/qti_worker.rb#L13-L49","documentation":"QtiWorker#perform requires the :qti_converter Canvas plugin to exist and be enabled; that plugin is only enabled when the python QTI converter tool is installed and configured. Without it, QTI export content migrations cannot run and the worker raises immediately after starting the job progress.","triggerScenarios":"Running a content migration / course export with QTI format on a Canvas installation where the python qti_converter plugin is not enabled — python tool missing, plugin settings disabled, or a plain Canvas install without the converter dependency.","commonSituations":"Self-hosted Canvas missing the python QTI converter package; plugin disabled in /plugins/qti_converter; Docker/dev environment without the python dependency; export attempted before infrastructure provisioning.","solutions":["Install the python QTI converter tool on the host running the migration job.","Enable the qti_converter plugin (Account > Plugins > QTI Converter) and verify plugin.settings[:enabled].","Verify the plugin configuration (paths/settings for the converter binary) and that the job process can execute it.","If the converter cannot be installed, use a different export format instead of QTI."],"exampleFix":"// before (shell on app host)\n# python converter not installed -> export fails\n// after\nsudo pip install the canvas qti converter tool   # or distro package\n# then in UI: Admin > Plugins > QTI Converter > Enable","handlingStrategy":"validation","validationCode":"plugin = Canvas::Plugin.find(:qti_converter)\nreturn :disabled unless plugin && plugin.settings[:enabled]","typeGuard":null,"tryCatchPattern":"begin\n  worker.perform(migration_id, cm)\nrescue RuntimeError => e\n  raise unless e.message.include?(\"Can't export QTI without the python converter tool\")\n  cm.workflow_state = 'failed' # surface actionable error to the user\n  cm.save!\nend","preventionTips":["Install the python QTI converter as part of base infrastructure provisioning.","Assert plugin enabled-ness in smoke tests before offering QTI export in the UI.","Hide the QTI export option when the qti_converter plugin is disabled."],"tags":["qti","export","missing-dependency","python","plugin"],"backgroundTag":"missing-dependency","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"}