instructure/canvas-lms · error · ImportError
Account not found "#
Error message
Account not found "#{account_id}" for course #{course_id} What it means
SisCourseImporter#add_course raises ImportError when account_id is present but no account in the root account's account tree has that sis_source_id. The importer looks up accounts by SIS id via @root_account.all_accounts; a non-blank account_id that resolves to nothing is a hard error, whereas a blank account_id silently falls back to fallback_account_id or the root account.
Solutions
- Ensure accounts.csv is imported before courses.csv in the same batch so referenced accounts exist
- Verify the account's sis_source_id matches exactly (case, whitespace, no renames) in accounts.csv
- Confirm the account belongs to the same root account the importer is running against
- If the account was intentionally removed, update or remove the course rows referencing it
- Use fallback_account_id (or leave account_id blank) if the course should land in a default subaccount
Example fix
// before course.add_course(id, term, "dept-eng-42", nil, status, ...) # dept-eng-42 not yet imported // after: import accounts first, or fall back importer.add_course(id, term, "dept-eng-42", "root-dept", status, ...) # fallback if primary missing
Defensive patterns
Strategy: validation
Validate before calling
known_accounts = root_account.all_accounts.pluck(:sis_source_id)
if row['account_id'].present? && !known_accounts.include?(row['account_id'])
raise ArgumentError, "unknown account_id #{row['account_id']} for course #{row['course_id']}"
end Type guard
nil
Try / catch
begin
importer.add_course(...)
rescue SisImport::ImportError => e
raise unless e.message.start_with?('Account not found')
failures << e.message # collect and re-run after accounts.csv is fixed/imported
end Prevention
- Always import accounts.csv before courses.csv
- Keep account sis_source_ids immutable once assigned; never rename in place
- Diff course rows' account_ids against existing accounts each batch
- Provide fallback_account_id for resilience to missing subaccounts
When it happens
Trigger: add_course called with account_id="acc-42" where no account with sis_source_id 'acc-42' exists under the root account — e.g. the account was deleted, lives under a different root, the sis_source_id was renamed, or the accounts.csv containing it was not imported (or imported in a later batch).
Common situations: courses.csv imported before its companion accounts.csv (ordering issue); account deleted in the SIS of record but still referenced by course rows; cross-subaccount typos or renames; multi-tenant setups where the account belongs to another root account.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- A course did not pass validation
- A # user did not pass validation (user: # , # : # , error…
- A (templated) course did not pass validation
- A # did not pass validation (# : # , error: # )
- A user did not pass validation
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/4d3f3f15b6f62b5a.
Report an issue: GitHub.
Appendix: source
Thrown at lib/sis/course_importer.rb:96
if course.nil?
course = Course.new
state_changes << :created
else
state_changes << :updated
end
course.saved_by = :sis_import
course_enrollment_term_id_stuck = course.stuck_sis_fields.include?(:enrollment_term_id)
if !course_enrollment_term_id_stuck && term_id
term = @root_account.enrollment_terms.active.find_by(sis_source_id: term_id)
end
course.enrollment_term = term if term
course.root_account = @root_account
account = nil
account = @root_account.all_accounts.find_by(sis_source_id: account_id) if account_id.present?
account ||= @root_account.all_accounts.find_by(sis_source_id: fallback_account_id) if fallback_account_id.present?
if account_id.present? && !account
raise ImportError, "Account not found \"#{account_id}\" for course #{course_id}"
end
course_account_stuck = course.stuck_sis_fields.include?(:account_id)
if !course_account_stuck && account&.active?
course.account = account
end
if course.account&.deleted?
raise ImportError, "Cannot restore course #{course_id} because the associated account #{course.account.sis_source_id} is deleted"
end
course.account ||= @root_account
update_account_associations = course.account_id_changed? || course.root_account_id_changed?
if account&.enable_as_k5_account? && friendly_name.present?
course.friendly_name = friendly_name
endView on GitHub (pinned to 1c9f0bb801)