instructure/canvas-lms · error · ImportError
Parent account didn't exist for #
Error message
Parent account didn't exist for #{account_id} What it means
When an account row specifies a parent_account_id, the importer resolves it from the accounts cache or via root_account.all_accounts.find_by(sis_source_id: ...). If no account with that SIS id exists, the parent reference cannot be satisfied and ImportError is raised. This prevents creating orphaned sub-accounts pointing at nonexistent parents.
Solutions
- Ensure the parent account row exists earlier in accounts.csv (or exists in Canvas with that sis_source_id).
- Fix typos/case mismatches in the parent_account_id value.
- Create/import the parent account before the child in the same SIS batch.
Example fix
// before
add_account('sub1', 'nonexistent_parent', 'active', 'Sub', nil)
// after
add_account('parent1', nil, 'active', 'Parent', nil)
add_account('sub1', 'parent1', 'active', 'Sub', nil) Defensive patterns
Strategy: validation
Validate before calling
unless parent_account_id.blank?
found = root_account.all_accounts.exists?(sis_source_id: parent_account_id)
raise "unknown parent #{parent_account_id}" unless found || batch.includes_account?(parent_account_id)
end Try / catch
begin
importer.add_account(id, parent_id, status, name, integration_id)
rescue SIS::BaseImporter::ImportError => e
logger.error("#{e.message}; ensure parents are ordered before children in accounts.csv")
end Prevention
- Order accounts.csv parents-before-children
- Run a referential-integrity pass over the CSV before import
- Keep sis_source_ids stable across SIS runs
When it happens
Trigger: add_account called with a parent_account_id that was never imported (or imported after this row), was deleted with its SIS id removed, or is misspelled/differs in case from the parent's sis_source_id.
Common situations: Row ordering in accounts.csv where child appears before parent; typos in parent_account_id; parent account deleted in a prior SIS run; importing a subset of accounts so the parent is absent from the batch and DB.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- Account with id "# " didn't exist for # #
- Course with id "# " didn't exist for # #
- A # did not pass validation (# : # , error: # )
- Cannot move # # because it has # in it.
- Cannot restore sub_account with ID: #
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/b5bda467249c751c.
Report an issue: GitHub.
Appendix: source
Thrown at lib/sis/account_importer.rb:59
def initialize(batch, root_account, logger)
@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
endView on GitHub (pinned to 1c9f0bb801)