instructure/canvas-lms · error · LastLinkToOutcomeNotDestroyed
Outcome '# ' cannot be deleted because it is aligned to…
Error message
Outcome '#{aligned_outcome}' cannot be deleted because it is aligned to content. What it means
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.
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.
Example fix
// before
content_tag.destroy
// after
if content_tag.can_destroy?
content_tag.destroy
else
outcome = content_tag.learning_outcome
raise UserFacingError, "Outcome '#{outcome.short_description}' is still aligned to content"
end Defensive patterns
Strategy: validation
Validate before calling
if content_tag.respond_to?(:can_destroy?) && !content_tag.can_destroy?
raise UserFacingError, "Outcome '#{content_tag.learning_outcome.short_description}' is still aligned"
end Try / catch
begin content_tag.destroy rescue LastLinkToOutcomeNotDestroyed => e flash[:error] = e.message end
Prevention
- Always check can_destroy? before destroying alignment tags
- Show aligned outcomes to users before module deletion
- Remove other alignments before deleting the last one
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Cannot archive a deleted LearningOutcome
- Cannot archive a deleted LearningOutcomeGroup
- Cannot modify outcome from another context
- Cannot unarchive a deleted LearningOutcome
- Child content tag was not found for #
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/5a0650708e3290d0.
Report an issue: GitHub.
Appendix: source
Thrown at app/models/content_tag.rb:472
alignment_conditions[:context_id] = context_id
alignment_conditions[:context_type] = context_type
end
@active_alignment_tags = ContentTag.learning_outcome_alignments.active.where(alignment_conditions)
if @active_alignment_tags.exists?
# then don't let them delete the link
return false
end
end
end
true
end
alias_method :destroy_permanently!, :destroy
def destroy
unless can_destroy?
aligned_outcome = @active_alignment_tags.map(&:learning_outcome).first.short_description
raise LastLinkToOutcomeNotDestroyed, "Outcome '#{aligned_outcome}' cannot be deleted because it is aligned to content."
end
context_module&.remove_completion_requirement(id)
self.workflow_state = "deleted"
save!
# for outcome links delete the associated friendly description
delete_outcome_friendly_description if content_type == "LearningOutcome"
run_submission_lifecycle_manager_for_quizzes_next(force: true)
update_module_item_submissions(change_of_module: false)
# after deleting the last native link to an unaligned outcome, delete the
# outcome. we do this here instead of in LearningOutcome#destroy because
# (a) LearningOutcome#destroy *should* only ever be called from here, and
# (b) we've already determined other_link and native
if @should_destroy_outcomeView on GitHub (pinned to 1c9f0bb801)