{"record":{"id":"ad05896d5dd5d1e6","repo":"instructure/canvas-lms","slug":"parent-references-not-found-prior-to-this-row-missing","errorCode":null,"errorMessage":"Parent references not found prior to this row: %{missing}","messagePattern":"Parent references not found prior to this row: %(.+?)","errorType":"exception","errorClass":"InvalidDataError","httpStatus":null,"severity":"error","filePath":"lib/outcomes/import.rb","lineNumber":321,"sourceCode":"      end\n      if object[:parent_guids].nil? || object[:parent_guids].blank?\n        group = [LearningOutcomeGroup.find(object[:learning_outcome_group_id])] if object[:learning_outcome_group_id]\n        group ||= [root_parent(given_context)]\n\n        return group\n      end\n\n      guids = object[:parent_guids].strip.split.uniq\n      possible_parents = LearningOutcomeGroup.where(outcome_import_id:, vendor_guid: guids)\n\n      # If allow_indirect is true, we could `filter{|g| child_context?(g.context) }`, but it is costly and\n      # redundant (since outcome_import_id matching is already enforced)\n      possible_parents = possible_parents.where(context: given_context) unless allow_indirect\n\n      found_guids = possible_parents.distinct.pluck(:vendor_guid)\n      if found_guids.length < guids.length\n        missing = guids - found_guids\n        raise InvalidDataError, I18n.t(\n          \"Parent references not found prior to this row: %{missing}\",\n          missing: missing.inspect\n        )\n      end\n\n      possible_parents\n    end\n\n    def child_context?(child, of: context)\n      return true if of.nil?\n\n      of == child || child.account_chain.include?(of)\n    end\n\n    def update_outcome_parents(outcome, parents, allow_indirect: false)\n      next_parent_ids = parents.pluck(:id)\n      existing_links = ContentTag.learning_outcome_links.where(content: outcome)\n      existing_parent_ids = existing_links.pluck(:associated_asset_id)","sourceCodeStart":303,"sourceCodeEnd":339,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/lib/outcomes/import.rb#L303-L339","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: child row references 'parent-x' not present earlier in the file\n[{\"vendor_guid\":\"child\",\"parent_guids\":[\"parent-x\"]}]\n// after: define the parent first\n[{\"vendor_guid\":\"parent-x\",\"title\":\"Parent\"},{\"vendor_guid\":\"child\",\"parent_guids\":[\"parent-x\"]}]","handlingStrategy":"validation","validationCode":"// Ruby: every parent guid must be pre-existing or defined earlier in the file\nknown = existing_guids + rows_before.map { |r| r[:vendor_guid] }\nmissing = row[:parent_guids] - known\nraise \"unresolved parents: #{missing.inspect}\" unless missing.empty?","typeGuard":null,"tryCatchPattern":"begin\n  importer.import_object(...)\nrescue Outcomes::Import::InvalidDataError => e\n  if e.message.start_with?('Parent references not found')\n    # reorder file so parents come first, then re-import\n  end\nend","preventionTips":["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."],"tags":["outcomes","import","foreign-key","ordering"],"backgroundTag":"referenced-record-not-found","analyzedSha":"1c9f0bb8013ed69c4f2efe11fd483025469b7e6c","analyzedAt":"2026-09-15T20:33:18.891Z","contentChangedAt":"2026-09-15T20:33:18.891Z","schemaVersion":2},"datasetVersion":"2026-09-23T02:17:17.105Z"}