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

  1. Add the missing parent group rows before the child row in the import file.
  2. Fix the parent_guids entries (typos, wrong guids).
  3. Import the complete export rather than a partial subset.
  4. 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

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


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)