instructure/canvas-lms · error · InvalidDataError
Parent references not found prior to this row
Error message
Parent references not found prior to this row: %{missing} What it means
find_parents resolves a row's parent_guids to existing LearningOutcomeGroups. If any parent guid cannot be found among groups available prior to this import row (scoped to the context unless allow_indirect), the import raises, because it refuses to guess or create implicit parents. The missing guids are listed in the message.
Solutions
- Add the missing parent group rows before the child row in the import file.
- Fix the parent_guids entries (typos, wrong guids).
- Import the complete export rather than a partial subset.
- Import into the same context (or use course_id rows to enable indirect parents) where the parents exist.
Example fix
// before: child row references 'parent-x' not present earlier in the file
[{"vendor_guid":"child","parent_guids":["parent-x"]}]
// after: define the parent first
[{"vendor_guid":"parent-x","title":"Parent"},{"vendor_guid":"child","parent_guids":["parent-x"]}] Defensive patterns
Strategy: validation
Validate before calling
// Ruby: every parent guid must be pre-existing or defined earlier in the file
known = existing_guids + rows_before.map { |r| r[:vendor_guid] }
missing = row[:parent_guids] - known
raise "unresolved parents: #{missing.inspect}" unless missing.empty? Try / catch
begin
importer.import_object(...)
rescue Outcomes::Import::InvalidDataError => e
if e.message.start_with?('Parent references not found')
# reorder file so parents come first, then re-import
end
end Prevention
- Topologically sort import rows: parents before children.
- Lint import files: every parent_guid must exist in the file or in the target context.
- Import whole exports, not fragments missing parent definitions.
When it happens
Trigger: A row's parent_guids contains a guid not defined by an earlier row of the same import nor pre-existing in the context; found_guids.length < guids.length at lib/outcomes/import.rb:321; called by import_group/import_outcome.
Common situations: Rows reordered so a child precedes its parent in the CSV/JSON; typos or case mismatches in parent guids; importing a subset of an export without its parent groups; importing into a sub-account while parents live in a different account.
Related errors
- Cannot modify outcome from another context
- Cyclic reference detected when importing
- Database error ( )
- Error importing outcomes
- File has no data
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/ad05896d5dd5d1e6.
Report an issue: GitHub.
Appendix: source
Thrown at lib/outcomes/import.rb:321
end
if object[:parent_guids].nil? || object[:parent_guids].blank?
group = [LearningOutcomeGroup.find(object[:learning_outcome_group_id])] if object[:learning_outcome_group_id]
group ||= [root_parent(given_context)]
return group
end
guids = object[:parent_guids].strip.split.uniq
possible_parents = LearningOutcomeGroup.where(outcome_import_id:, vendor_guid: guids)
# If allow_indirect is true, we could `filter{|g| child_context?(g.context) }`, but it is costly and
# redundant (since outcome_import_id matching is already enforced)
possible_parents = possible_parents.where(context: given_context) unless allow_indirect
found_guids = possible_parents.distinct.pluck(:vendor_guid)
if found_guids.length < guids.length
missing = guids - found_guids
raise InvalidDataError, I18n.t(
"Parent references not found prior to this row: %{missing}",
missing: missing.inspect
)
end
possible_parents
end
def child_context?(child, of: context)
return true if of.nil?
of == child || child.account_chain.include?(of)
end
def update_outcome_parents(outcome, parents, allow_indirect: false)
next_parent_ids = parents.pluck(:id)
existing_links = ContentTag.learning_outcome_links.where(content: outcome)
existing_parent_ids = existing_links.pluck(:associated_asset_id)View on GitHub (pinned to 1c9f0bb801)