{"record":{"id":"5a0650708e3290d0","repo":"instructure/canvas-lms","slug":"outcome-aligned-outcome-cannot-be-deleted-because-it-is","errorCode":null,"errorMessage":"Outcome '#{aligned_outcome}' cannot be deleted because it is aligned to content.","messagePattern":"Outcome '#(.+?)' cannot be deleted because it is aligned to content\\.","errorType":"exception","errorClass":"LastLinkToOutcomeNotDestroyed","httpStatus":null,"severity":"error","filePath":"app/models/content_tag.rb","lineNumber":472,"sourceCode":"          alignment_conditions[:context_id] = context_id\n          alignment_conditions[:context_type] = context_type\n        end\n\n        @active_alignment_tags = ContentTag.learning_outcome_alignments.active.where(alignment_conditions)\n        if @active_alignment_tags.exists?\n          # then don't let them delete the link\n          return false\n        end\n      end\n    end\n    true\n  end\n\n  alias_method :destroy_permanently!, :destroy\n  def destroy\n    unless can_destroy?\n      aligned_outcome = @active_alignment_tags.map(&:learning_outcome).first.short_description\n      raise LastLinkToOutcomeNotDestroyed, \"Outcome '#{aligned_outcome}' cannot be deleted because it is aligned to content.\"\n    end\n\n    context_module&.remove_completion_requirement(id)\n\n    self.workflow_state = \"deleted\"\n    save!\n\n    # for outcome links delete the associated friendly description\n    delete_outcome_friendly_description if content_type == \"LearningOutcome\"\n\n    run_submission_lifecycle_manager_for_quizzes_next(force: true)\n    update_module_item_submissions(change_of_module: false)\n\n    # after deleting the last native link to an unaligned outcome, delete the\n    # outcome. we do this here instead of in LearningOutcome#destroy because\n    # (a) LearningOutcome#destroy *should* only ever be called from here, and\n    # (b) we've already determined other_link and native\n    if @should_destroy_outcome","sourceCodeStart":454,"sourceCodeEnd":490,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/models/content_tag.rb#L454-L490","documentation":"ContentTag#destroy raises LastLinkToOutcomeNotDestroyed when can_destroy? is false, i.e. the tag is the last alignment keeping the learning outcome attached to content. Destroying it would orphan an outcome that is still aligned, so Canvas blocks the soft delete and names the outcome in the message.","triggerScenarios":"Deleting a module item / alignment whose content_tag is the final link between its learning_outcome and content; deleting outcomes via migrations or API calls that remove the last alignment tag.","commonSituations":"Cleaning up course modules that still host an assessed outcome; outcome import/export jobs removing alignments; teachers deleting a module containing the only aligned item for an outcome.","solutions":["Remove or replace other alignments for the outcome first so this tag is no longer the last link, then retry destroy.","If the outcome itself should go, delete the learning outcome through the outcomes API instead of destroying its alignment tag.","Guard the delete with can_destroy? and show the outcome's short_description in a user-facing message."],"exampleFix":"// before\ncontent_tag.destroy\n// after\nif content_tag.can_destroy?\n  content_tag.destroy\nelse\n  outcome = content_tag.learning_outcome\n  raise UserFacingError, \"Outcome '#{outcome.short_description}' is still aligned to content\"\nend","handlingStrategy":"validation","validationCode":"if content_tag.respond_to?(:can_destroy?) && !content_tag.can_destroy?\n  raise UserFacingError, \"Outcome '#{content_tag.learning_outcome.short_description}' is still aligned\"\nend","typeGuard":null,"tryCatchPattern":"begin\n  content_tag.destroy\nrescue LastLinkToOutcomeNotDestroyed => e\n  flash[:error] = e.message\nend","preventionTips":["Always check can_destroy? before destroying alignment tags","Show aligned outcomes to users before module deletion","Remove other alignments before deleting the last one"],"tags":["outcomes","content-tags","alignment","delete-blocked"],"backgroundTag":"operation-blocked-by-dependency","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"}