{"record":{"id":"7ad444f9786d26d5","repo":"instructure/canvas-lms","slug":"cannot-change-column-captions-locked-by-master-course","errorCode":null,"errorMessage":"cannot change column: captions - locked by Master Course","messagePattern":"cannot change column: captions - locked by Master Course","errorType":"validation","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"app/models/media_track.rb","lineNumber":65,"sourceCode":"  validates :kind, inclusion: { in: %w[subtitles captions descriptions chapters metadata] }\n  validates :content, presence: true, unless: -> { it.asr? && (it.processing? || it.failed?) }\n  validates :locale, format: { with: /\\A[A-Za-z-]+\\z/ }, uniqueness: { scope: :attachment_id, unless: -> { it.attachment_id.blank? } }\n  restrict_columns :content, %i[attachment_id content locale media_object_id webvtt_content external_id]\n\n  RE_LOOKS_LIKE_TTML = /<tt\\s+xml/i\n  validates :content, format: {\n    without: RE_LOOKS_LIKE_TTML,\n    message: ->(_object, _data) { t(\"TTML tracks are not allowed because they are susceptible to xss attacks\") }\n  }\n\n  # MasterCourses::CollectionRestrictor handles soft-deletes, but doesn't handle\n  # hard deletes well. One day we  might want to standardize this to more hard\n  # deleted objects.\n  def check_for_restricted_updates\n    return true if skip_restrictions? || attachment&.skip_restrictions?\n    return unless attachment&.child_content_restrictions&.dig(:content)\n\n    raise \"cannot change column: captions - locked by Master Course\"\n  end\n\n  def set_media_and_attachment\n    self.attachment_id ||= media_object.attachment_id\n    self.media_object_id ||= attachment.media_object_by_media_id\n  end\n\n  def webvtt_content\n    super || content\n  end\n\n  def convert_srt_to_wvtt\n    return if content.blank?\n\n    if content.exclude?(\"WEBVTT\") && (content_changed? || self[\"webvtt_content\"].nil?)\n      srt_content = content.dup\n      srt_content.gsub!(/(:|^)(\\d)(,|:)/, '\\10\\2\\3')\n      srt_content.gsub!(/([0-9]{2}:[0-9]{2}:[0-9]{2})(,)([0-9]{3})/, '\\1.\\3')","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/models/media_track.rb#L47-L83","documentation":"MediaTrack#check_for_restricted_updates runs as a validation before save. If the media track's attachment belongs to child content locked by a master course's :content restrictions, any change (e.g. uploading new captions) is blocked with 'cannot change column: captions - locked by Master Course'.","triggerScenarios":"Creating/updating a MediaTrack whose attachment.child_content_restrictions includes :content while the object is child content of a blueprint course and restrictions are not skipped.","commonSituations":"Uploading replacement captions for a media file attached to a locked blueprint course item; imports touching master-locked media; users editing captions in a locked child course section.","solutions":["Unlock the related content in the master course (remove content lock) so child captions can change","Make the caption edit in the master course and sync to associated courses","If legitimate (e.g. migration/import), ensure skip_restrictions? applies (set @importing_migration or @skip_downstream_changes)"],"exampleFix":"// before\nattachment.media_tracks.create!(...)\n// after\nunless attachment.child_content_restrictions&.dig(:content)\n  attachment.media_tracks.create!(...)\nend","handlingStrategy":"try-catch","validationCode":"if track.attachment&.child_content_restrictions&.dig(:content)\n  # surface UI message instead of attempting save\nend","typeGuard":null,"tryCatchPattern":"begin\n  media_track.save!\nrescue RuntimeError => e\n  raise unless e.message.include?('locked by Master Course')\n  flash[:error] = I18n.t('Captions are locked by the master course')\nend","preventionTips":["Check child_content_restrictions before enabling caption editing in the UI","Apply caption changes in the master course and let sync propagate"],"tags":["ruby","blueprint-courses","media","validation"],"backgroundTag":"permission-denied","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"}