{"record":{"id":"61a33579bf6fa2d9","repo":"instructure/canvas-lms","slug":"outcome-with-canvas-id-id-not-found","errorCode":null,"errorMessage":"Outcome with canvas id \"%{id}\" not found","messagePattern":"Outcome with canvas id \"%(.+?)\" not found","errorType":"exception","errorClass":"InvalidDataError","httpStatus":null,"severity":"error","filePath":"lib/outcomes/import.rb","lineNumber":245,"sourceCode":"        prior\n      else\n        current\n      end\n    end\n\n    def non_vendor_guid_changes?(model)\n      model.has_changes_to_save? && !(model.changes_to_save.length == 1 &&\n        model.changes_to_save.key?(\"vendor_guid\"))\n    end\n\n    def find_prior_outcome(outcome)\n      match = /canvas_outcome:(\\d+)/.match(outcome[:vendor_guid])\n      if match\n        canvas_id = match[1]\n        begin\n          LearningOutcome.find(canvas_id)\n        rescue ActiveRecord::RecordNotFound\n          raise InvalidDataError, I18n.t(\n            'Outcome with canvas id \"%{id}\" not found',\n            id: outcome[:canvas_id]\n          )\n        end\n      else\n        vendor_guid = outcome[:vendor_guid]\n        prior = LearningOutcome.where(vendor_guid:).active_first.first\n        return prior if prior\n\n        LearningOutcome.new(vendor_guid:)\n      end\n    end\n\n    def find_prior_group(group, group_context)\n      vendor_guid = group[:vendor_guid]\n      prior = LearningOutcomeGroup.where(context: group_context).where(vendor_guid:).active_first.first\n      return prior if prior\n","sourceCodeStart":227,"sourceCodeEnd":263,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/lib/outcomes/import.rb#L227-L263","documentation":"find_prior_outcome resolves vendor_guids of the form 'canvas_outcome:<id>' to an existing LearningOutcome by primary key. If LearningOutcome.find raises ActiveRecord::RecordNotFound, the import converts it to this InvalidDataError. Note the message interpolates outcome[:canvas_id] rather than the matched canvas_id, so it can render blank; the guid in the row is the id to check.","triggerScenarios":"A vendor_guid like 'canvas_outcome:12345' where no LearningOutcome with id 12345 exists (deleted outcome, wrong shard, or fabricated id); hit in find_prior_outcome (lib/outcomes/import.rb:245), called by import_outcome.","commonSituations":"Re-importing an export after the referenced outcome was deleted; exporting from one Canvas instance and importing into another where ids differ; hand-crafted import files with guessed ids.","solutions":["Verify the canvas id exists (GET /api/v1/outcomes/:id) and correct the vendor_guid.","If the outcome was deleted, remove the row or change to a new vendor_guid so the outcome is created fresh.","If migrating between instances, replace canvas_outcome:<id> refs with real vendor_guids instead of internal ids."],"exampleFix":"// before\n\"vendor_guid\": \"canvas_outcome:99999\"  // nonexistent\n// after\n\"vendor_guid\": \"canvas_outcome:1234\"   // existing outcome id","handlingStrategy":"validation","validationCode":"// Ruby: verify the canvas id exists before import\nif (m = /canvas_outcome:(\\d+)/.match(guid))\n  raise 'missing outcome' unless LearningOutcome.where(id: m[1]).exists?\nend","typeGuard":null,"tryCatchPattern":"begin\n  importer.import_object(...)\nrescue Outcomes::Import::InvalidDataError => e\n  raise unless e.message.include?('not found')\n  # drop or recreate the row with a fresh vendor_guid\nend","preventionTips":["Never reference internal canvas ids across Canvas instances/shards.","Re-verify canvas_outcome: ids after deletions or migrations.","Prefer stable external vendor_guids over canvas_outcome:<id> references."],"tags":["outcomes","import","record-not-found","canvas-id"],"backgroundTag":"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"}