{"record":{"id":"840401384803b08d","repo":"instructure/canvas-lms","slug":"no-migration-file-required-for-content","errorCode":"no_migration_file","errorMessage":"File required for content migration.","messagePattern":"File required for content migration\\.","errorType":"exception","errorClass":"Canvas::Migration::Error","httpStatus":null,"severity":"error","filePath":"lib/canvas/migration/worker/zip_file_worker.rb","lineNumber":37,"sourceCode":"#\nclass Canvas::Migration::Worker::ZipFileWorker < Canvas::Migration::Worker::Base\n  def perform(cm = nil)\n    cm ||= ContentMigration.find migration_id\n    cm.save if cm.capture_job_id\n\n    cm.workflow_state = :importing\n    cm.migration_settings[:skip_import_notification] = true\n    cm.job_progress.start\n    cm.save\n\n    begin\n      if cm.attachment\n        zipfile = cm.attachment.open\n      elsif cm.migration_settings[:file_url]\n        att = Canvas::Migration::Worker.download_attachment(cm, cm.migration_settings[:file_url])\n        zipfile = att.open\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      folder = cm.context.folders.find(cm.migration_settings[:folder_id])\n\n      update_callback = lambda do |pct|\n        percent_complete = pct * 100\n\n        scaled = percent_complete\n\n        if cm.import_immediately?\n          scaled = (scaled / 2) + 50\n        end\n\n        # Only update if progress has incremented 1 percent\n        if scaled - cm.progress >= 1\n          cm.update_import_progress(percent_complete)\n        end\n      end","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/lib/canvas/migration/worker/zip_file_worker.rb#L19-L55","documentation":"ZipFileWorker#perform requires an archive source: the content migration's attachment, or a file_url to download. If neither exists (and settings do not disable the archive-file requirement), Canvas::Migration::Error with 'File required for content migration.' is raised (I18n key :no_migration_file).","triggerScenarios":"Performing a zip_file_importer / unzip migration when cm.attachment is nil and cm.migration_settings[:file_url] is not set.","commonSituations":"Creating a ContentMigration via API without attaching a file or passing file_url, attachment deleted before the job ran, migration settings lost between queueing and processing.","solutions":["Attach a file to the content migration (cm.attachment = ...) or set cm.migration_settings[:file_url] before queueing the job","Re-run the import through the UI so the upload completes before the worker processes","Verify the attachment wasn't deleted/failed upload (check file_state) between enqueue and perform","For API-driven migrations, include file_url in migration_settings when not uploading directly"],"exampleFix":"// before (API body)\n{ \"migration_type\": \"zip_file_importer\", \"settings\": { \"folder_id\": 12 } }\n// after\n{ \"migration_type\": \"zip_file_importer\", \"settings\": { \"folder_id\": 12, \"file_url\": \"https://files.example.com/pkg.zip\" } }","handlingStrategy":"validation","validationCode":"raise 'no source file' if cm.attachment.nil? && cm.migration_settings[:file_url].blank?","typeGuard":"has_source = !cm.attachment.nil? || cm.migration_settings[:file_url].present?","tryCatchPattern":"begin\n  cm.run\nrescue Canvas::Migration::Error => e\n  if e.message.include?('File required')\n    redirect_to upload_step_path(cm)\n  end\nend","preventionTips":["Require file upload in the UI before allowing import submission","Guard API endpoints to accept attachment or file_url","Check attachment file_state is not 'errored'/'deleted' before queueing"],"tags":["content-migration","zip","missing-file"],"backgroundTag":"missing-required-argument","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"}