instructure/canvas-lms · warning · MigrationRunningError

cannot start new migration while another one is running

Error message

cannot start new migration while another one is running

What it means

MasterCourses::MasterMigration.start_new_migration! checks master_template.active_migration_running?; if a migration is already in progress and opts[:retry_later] is not set, it raises MigrationRunningError with this message. Canvas allows only one active master-course migration per template at a time.

Solutions

  1. Pass retry_later: true so Canvas reschedules the migration in 10 minutes instead of raising.
  2. Wait for the current migration to finish before starting a new one (check master_template.active_migration_running?).
  3. If the active migration is genuinely stuck, clear the stale state (reset master_template.active_migration / inspect the delayed job) and retry.
  4. Debounce/dedupe UI or API triggers so concurrent sync requests don't pile up.

Example fix

// before
MasterCourses::MasterMigration.start_new_migration!(template, user)
// after
MasterCourses::MasterMigration.start_new_migration!(template, user, retry_later: true)
Defensive patterns

Strategy: try-catch

Validate before calling

if template.active_migration_running?
  MasterCourses::MasterMigration.start_new_migration!(template, user, retry_later: true)
else
  MasterCourses::MasterMigration.start_new_migration!(template, user)
end

Try / catch

begin
  MasterCourses::MasterMigration.start_new_migration!(template, user)
rescue MasterCourses::MasterMigration::MigrationRunningError
  # notify user a migration is already running; retry later
end

Prevention

When it happens

Trigger: Calling start_new_migration! (or triggering an export/sync via API or UI) while the template's previous migration is still queued/running, without passing retry_later: true.

Common situations: Users clicking 'sync' repeatedly while a large migration runs; scheduled/automated sync jobs overlapping manual migrations; a stuck previous migration (failed delayed job) that never cleared active_migration, blocking all new ones.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at app/models/master_courses/master_migration.rb:76

    state :completed # after all the imports have run (successfully hopefully)
    state :exports_failed # if we break during export
    state :imports_failed # if one or more of the imports failed
  end

  class MigrationRunningError < StandardError; end

  # create a new migration and queue it up (if we can)
  def self.start_new_migration!(master_template, user, opts = {})
    master_template.class.transaction do
      master_template.lock!
      if master_template.active_migration_running?
        if opts[:retry_later]
          delay(singleton: "retry_start_master_migration_#{master_template.global_id}",
                run_at: 10.minutes.from_now)
            .start_new_migration!(master_template, user, opts)
        else
          raise MigrationRunningError, "cannot start new migration while another one is running"
        end
      else
        new_migration = master_template.master_migrations.create!({ user: }.merge(opts.except(:retry_later, :priority)))
        master_template.active_migration = new_migration
        master_template.save!
        new_migration.queue_export_job(priority: opts[:priority] || Delayed::LOW_PRIORITY)
        new_migration
      end
    end
  end

  def copy_settings=(val)
    migration_settings[:copy_settings] = val
  end

  def send_item_notifications=(val)
    migration_settings[:send_item_notifications] = val
  end

View on GitHub (pinned to 1c9f0bb801)