{"record":{"id":"73799a510420d5e2","repo":"instructure/canvas-lms","slug":"no-local-app-lti-registration-found-for-registration-id-old","errorCode":null,"errorMessage":"No local App/Lti::Registration found for registration_id=#{old_registration_id}","messagePattern":"No local App/Lti::Registration found for registration_id=#(.+?)","errorType":"exception","errorClass":"Lti::LocalAppNotFound","httpStatus":null,"severity":"error","filePath":"app/models/lti/context_control.rb","lineNumber":367,"sourceCode":"\n    resolved_root_account = deployment&.root_account\n    cross_shard = shard != Shard.shard_for(old_registration_id)\n    same_shard_inherited = !cross_shard &&\n                           resolved_root_account != Account.site_admin &&\n                           shard == Account.site_admin.shard &&\n                           old_registration&.root_account == Account.site_admin\n\n    if cross_shard || same_shard_inherited\n      local = Lti::Registration.active.find_by(\n        template_registration_id: old_registration_id,\n        account: resolved_root_account\n      )\n      if local\n        self.app_id = local.id\n      else\n        msg = \"No local App/Lti::Registration found for registration_id=#{old_registration_id}\"\n        if resolved_root_account&.feature_enabled?(:lti_registrations_templates)\n          raise Lti::LocalAppNotFound, msg\n        else\n          Canvas::Errors.capture_exception(:lti_registration_sync, msg, :warn)\n        end\n      end\n    else\n      self.app_id = old_registration_id\n    end\n  end\n\n  def context_belongs_to_deployment\n    return unless (account_id || course_id) && deployment\n\n    if deployment.context_type == \"Course\"\n      # context can only be the course itself\n      unless course_id == deployment.context_id\n        errors.add(:context, I18n.t(\"must be the deployment's context\"))\n      end\n    else","sourceCodeStart":349,"sourceCodeEnd":385,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/models/lti/context_control.rb#L349-L385","documentation":"Lti::ContextControl#sync_app_id tries to resolve an old registration_id to a local Lti::Registration/App. When no local record is found, behavior depends on the root account feature flag lti_registrations_templates: if enabled it raises Lti::LocalAppNotFound; otherwise it logs a warning via Canvas::Errors and continues.","triggerScenarios":"Syncing a ContextControl whose stored registration_id does not correspond to any local Lti::Registration/App, while the resolved root account has the lti_registrations_templates feature enabled.","commonSituations":"Data migrated or imported from another shard/environment where the registration does not exist locally; stale registration_id after deleting a registration; accounts with the feature flag on but incomplete registration backfill.","solutions":["Create/backfill the missing local Lti::Registration matching old_registration_id before syncing","Verify old_registration_id points to a registration that exists on the same shard","If legacy data is expected, disable the lti_registrations_templates feature on the root account so sync degrades to a warning instead of raising","Rescue Lti::LocalAppNotFound at the sync call site and handle the missing-app case"],"exampleFix":"// before\ncontrol.update!(app_id: old_registration_id) # raises when flag on\n// after\nbegin\n  control.sync_app_id\nrescue Lti::LocalAppNotFound => e\n  Canvas::Errors.capture_exception(:lti_registration_sync, e, :warn)\nend","handlingStrategy":"try-catch","validationCode":"unless Lti::Registration.where(id: old_registration_id).exists? then handle_missing_app end","typeGuard":"def local_app_present?(id) = Lti::Registration.exists?(id)","tryCatchPattern":"begin\n  context_control.sync_app_id\nrescue Lti::LocalAppNotFound => e\n  Canvas::Errors.capture_exception(:lti_registration_sync, e, :warn)\nend","preventionTips":["Backfill local registrations before enabling lti_registrations_templates","Verify registration_ids exist on the same shard","Rescue Lti::LocalAppNotFound at sync boundaries"],"tags":["lti","registration","feature-flag"],"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"}