instructure/canvas-lms · error · Canvas::Migration::Error

att.upload_error_message

Error message

att.upload_error_message

What it means

In Canvas::Migration::Worker#download_and_import_attachment (attachment cloning from a file_url), after att.clone_url the attachment is checked for file_state == 'errored'; if so, the attachment's upload_error_message is raised as Canvas::Migration::Error. It signals InstFS/S3 upload of the cloned URL failed.

Solutions

  1. Check the rendered message (att.upload_error_message) for the concrete cause (quota, 404, etc.)
  2. Verify the source file_url is still valid and publicly resolvable from the server/InstFS
  3. Ensure the migration context has enough quota; the rescue below maps OverQuotaError separately
  4. Retry the migration; transient storage failures mark the attachment errored

Example fix

// before (caller)
att = Canvas::Migration::Worker.download_attachment(cm, url)
// after
begin
  att = Canvas::Migration::Worker.download_attachment(cm, url)
rescue Canvas::Migration::Error => e
  cm.fail_with_error!(e)
end
Defensive patterns

Strategy: try-catch

Try / catch

begin
  att = Canvas::Migration::Worker.download_attachment(cm, url)
rescue Canvas::Migration::Error => e
  cm.fail_with_error!(e)
end

Prevention

When it happens

Trigger: Canvas::Migration::Worker.download_attachment called with a file_url whose clone_url fails — unreachable or expired URL, quota exceeded flagging errored state, InstFS rejection.

Common situations: Course copy referencing external file URLs that expired, source attachments deleted, inst-fs/S3 outage during migration, oversized file exceeding quota.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at lib/canvas/migration/worker.rb:95

  def self.clear_exported_data(folder)
    config = ConfigFile.load("external_migration")
    if (!config || !config[:keep_after_complete]) && File.exist?(folder)
      FileUtils.rm_rf(folder)
    end
  rescue
    Rails.logger.warn "Couldn't clear export data for content_migration #{content_migration.id}"
  end

  def self.download_attachment(cm, url)
    att = Attachment.new
    att.context = cm
    att.file_state = "deleted"
    att.workflow_state = "unattached"
    att.clone_url(url, false, true, quota_context: cm.context)

    if att.file_state == "errored"
      raise Canvas::Migration::Error, att.upload_error_message
    end

    cm.attachment = att
    cm.save!
    att
  rescue Attachment::OverQuotaError
    raise Canvas::Migration::Error, $!.message
  end
end

View on GitHub (pinned to 1c9f0bb801)