instructure/canvas-lms · error · ImportError

Cannot restore sub_account with ID: #

Error message

Cannot restore sub_account with ID: #{account_id} because parent_account with ID: #{parent_account_id} has been deleted.

What it means

If the referenced parent account exists but its workflow_state is 'deleted', the importer refuses to attach the (new) sub-account to it, raising ImportError. Re-parenting under a deleted account would produce an account buried under an inactive subtree, so it's blocked explicitly.

Solutions

  1. Re-activate the parent account first (import it with status 'active'), then import the child.
  2. Re-point the child's parent_account_id to an active account.
  3. Delete the child row if it is no longer needed.

Example fix

// before
add_account('sub1', 'old_deleted_parent', 'active', 'Sub', nil)
// after
add_account('old_deleted_parent', nil, 'active', 'Parent', nil)
add_account('sub1', 'old_deleted_parent', 'active', 'Sub', nil)
Defensive patterns

Strategy: validation

Validate before calling

parent = root_account.all_accounts.find_by(sis_source_id: parent_account_id)
raise "parent deleted" if parent&.workflow_state == "deleted"

Try / catch

begin
  importer.add_account(id, parent_id, status, name, integration_id)
rescue SIS::BaseImporter::ImportError => e
  if e.message.include?("has been deleted")
    reactivate_parent_then_retry
  end
end

Prevention

When it happens

Trigger: add_account called with a new account (or one without a valid existing record) whose parent_account_id resolves to an account where parent.workflow_state == 'deleted'.

Common situations: Re-importing accounts after the parent was soft-deleted in a previous SIS run; restoring a sub-account while its parent remains deleted; stale SIS data referencing a decommissioned account.

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/bc6704199e31934a. Report an issue: GitHub.

Appendix: source

Thrown at lib/sis/account_importer.rb:60

        @batch = batch
        @root_account = root_account
        @accounts_cache = {}
        @roll_back_data = []
        @logger = logger
        @success_count = 0
        @accounts_to_set_sis_batch_ids = Set.new
      end

      def add_account(account_id, parent_account_id, status, name, integration_id)
        raise ImportError, "No account_id given for an account" if account_id.blank?
        return if @batch.skip_deletes? && status =~ /deleted/i

        parent = nil
        unless parent_account_id.blank?
          parent = @accounts_cache[parent_account_id]
          parent ||= @root_account.all_accounts.find_by(sis_source_id: parent_account_id)
          raise ImportError, "Parent account didn't exist for #{account_id}" unless parent
          raise ImportError, "Cannot restore sub_account with ID: #{account_id} because parent_account with ID: #{parent_account_id} has been deleted." if parent.workflow_state == "deleted"

          @accounts_cache[parent.sis_source_id] = parent
        end

        account = @accounts_cache[account_id]
        account ||= @root_account.all_accounts.find_by(sis_source_id: account_id)
        if account.nil?
          raise ImportError, "No name given for account #{account_id}, skipping" if name.blank?
          raise ImportError, "Improper status \"#{status}\" for account #{account_id}, skipping" unless /\A(active|deleted)/i.match?(status)
        end

        account ||= @root_account.sub_accounts.new

        account.root_account = @root_account
        if account.new_record? || !account.stuck_sis_fields.include?(:parent_account_id) || Account.sis_stickiness_options[:add_sis_stickiness]
          account.parent_account = parent || @root_account
        end

View on GitHub (pinned to 1c9f0bb801)