instructure/canvas-lms · error · Canvas::Migration::Error
File required for content migration.
Error message
File required for content migration.
What it means
CC::Importer::CCWorker#perform starts a content-migration conversion job. Before instantiating the converter it needs a source package: it looks for an attachment on the ContentMigration, then a file_url to download, and finally honors a no_archive_file escape hatch. If none of the three exist, it raises Canvas::Migration::Error with 'File required for content migration.' because there is no archive to convert.
Solutions
- Re-create or re-upload the migration with a valid file attachment (check cm.attachment_id is set before enqueueing).
- If migrating by URL, set migration_settings[:file_url] to a reachable archive URL so the worker can download it.
- If the migration intentionally has no archive (e.g. copy by source course ID), set migration_settings[:no_archive_file] = true and supply migration_settings[:converter_class].
- Inspect the failed ContentMigration's migration_settings to see which of attachment/file_url/no_archive_file was expected but missing.
Example fix
# before migration = course.content_migrations.create! migration.migration_settings[:migration_type] = 'canvas_cartridge_importer' migration.save! migration.queue_migration # after migration = course.content_migrations.create! migration.attachment = uploaded_zip_attachment migration.migration_settings[:migration_type] = 'canvas_cartridge_importer' migration.save! migration.queue_migration
Defensive patterns
Strategy: validation
Validate before calling
raise 'attachment required' unless cm.attachment || cm.migration_settings[:file_url] || cm.migration_settings[:no_archive_file] cm.queue_migration
Type guard
def migration_has_source?(cm) cm.attachment.present? || cm.migration_settings[:file_url].present? || cm.migration_settings[:no_archive_file] == true end
Try / catch
begin
worker.perform(cm)
rescue Canvas::Migration::Error => e
if e.message.include?("File required")
cm.fail_with_error!(e)
else
raise
end
end Prevention
- Validate the migration has an attachment, file_url, or no_archive_file before enqueueing
- In API integrations, assert the uploaded file attached successfully before returning 2xx
- Watch for job requeues that may outlive the attachment record
When it happens
Trigger: A ContentMigration is queued with no cm.attachment, no migration_settings[:file_url], and no migration_settings[:no_archive_file] — e.g. an upload request created the migration record but the attachment failed to attach, or an API client kicked off the job without posting the file.
Common situations: Multipart upload dropped the file before the job ran; a course-copy/import API call was made with neither a file nor a source_course; a background job was requeued after the attachment record was deleted; custom integrations calling the imports API without the export_file parameter.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- Error identifying package type
- No exported data to import
- no_migration_file
- A new_id, '# ', referenced an existing # and the # with #…
- A new_integration_id, '#
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/1581f842eee77acc.
Report an issue: GitHub.
Appendix: source
Thrown at lib/cc/importer/cc_worker.rb:40
cm ||= ContentMigration.where(id: migration_id).first
cm.save if cm.capture_job_id
cm.job_progress.start unless cm.skip_job_progress
begin
cm.update_conversion_progress(1)
settings = cm.migration_settings.clone
settings[:content_migration_id] = migration_id
settings[:user_id] = cm.user_id
settings[:content_migration] = cm
settings[:is_discussion_checkpoints_enabled] = discussion_checkpoints_enabled?(cm)
if cm.attachment
settings[:attachment_id] = cm.attachment.id
elsif settings[:file_url]
# create attachment and download file
att = Canvas::Migration::Worker.download_attachment(cm, settings[:file_url])
settings[:attachment_id] = att.id
elsif !settings[:no_archive_file]
raise Canvas::Migration::Error, I18n.t(:no_migration_file, "File required for content migration.")
end
converter_class = settings[:converter_class]
unless converter_class
if settings[:no_archive_file]
raise ArgumentError, "converter_class required for content migration with no file"
end
settings[:archive] = Canvas::Migration::Archive.new(settings)
converter_class = settings[:archive].get_converter
end
converter = converter_class.new(settings)
course = converter.export
export_folder_path = course[:export_folder_path]
overview_file_path = course[:overview_file_path]
if overview_file_pathView on GitHub (pinned to 1c9f0bb801)