{"record":{"id":"f8eb490539ceac20","repo":"instructure/canvas-lms","slug":"invalid-assignment-override-id-override-data-id-for","errorCode":null,"errorMessage":"invalid assignment override id #{override_data[\"id\"]} for assignment #{assignment.id}","messagePattern":"invalid assignment override id #(.+?) for assignment #(.+?)","errorType":"exception","errorClass":"ActiveRecord::RecordNotFound","httpStatus":404,"severity":"error","filePath":"app/models/assignment/bulk_update.rb","lineNumber":57,"sourceCode":"      next unless dates.present?\n\n      base, overrides = dates.partition { |date| date[\"base\"] }\n\n      # 1a. update the assignment\n      assignment = assignments[id.to_i]\n      raise ActiveRecord::RecordNotFound, \"invalid assignment id #{id}\" unless assignment\n\n      if base.any?\n        assignment.content_being_saved_by(@current_user)\n        assignment.updating_user = @current_user\n        assignment.assign_attributes(base.first.slice(*%w[due_at unlock_at lock_at]))\n        assignments_to_save << assignment if assignment.changed?\n      end\n\n      # 1b. update associated overrides\n      overrides.each do |override_data|\n        override = assignment.assignment_overrides.detect { |o| o.id == override_data[\"id\"].to_i }\n        raise ActiveRecord::RecordNotFound, \"invalid assignment override id #{override_data[\"id\"]} for assignment #{assignment.id}\" unless override\n\n        %w[due_at unlock_at lock_at].each do |date|\n          if override_data.key?(date)\n            override.send(:\"#{date}=\", override_data[date])\n            override.send(:\"#{date}_overridden=\", true)\n          else\n            override.send(:\"#{date}=\", nil)\n            override.send(:\"#{date}_overridden=\", false)\n          end\n        end\n        assignments_to_save << assignment if override.changed?\n      end\n    end\n\n    progress_count = 0\n    progress_total = assignments_to_save.size * 2\n\n    # 2. validate all assignments and overrides","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/models/assignment/bulk_update.rb#L39-L75","documentation":"In Assignment::BulkUpdate#run, after locating the assignment, each override entry must match an AssignmentOverride belonging to that assignment (matched by id in the loaded association). If no override with that id exists on the assignment, it raises ActiveRecord::RecordNotFound 'invalid assignment override id X for assignment Y'. This guards against updating overrides from a different assignment or deleted overrides.","triggerScenarios":"Payload references an override id belonging to a different assignment; the override was deleted (e.g. section removed) before the bulk update; override id belongs to an assignment the user can't see; id passed as string that doesn't .to_i-match any loaded override.","commonSituations":"Stale bulk-edit UI after another teacher deleted an override; copy/paste of override ids across assignments in API scripts; client bug sending all overrides under the wrong assignment key.","solutions":["Re-fetch assignment overrides immediately before the bulk update and filter payload entries to existing ids","Confirm override ids belong to the same assignment as the enclosing entry (assignment_id check client-side)","Handle deleted overrides gracefully by dropping them from the payload instead of raising","Rescue ActiveRecord::RecordNotFound and surface which override/assignment pair was invalid"],"exampleFix":"// before\noverrides.each { |o| run_entry(assignment, o) } # may reference stale ids\n// after\nvalid = assignment.assignment_overrides.reload.map(&:id)\noverrides.select { |o| valid.include?(o[\"id\"].to_i) }.each { |o| run_entry(assignment, o) }","handlingStrategy":"try-catch","validationCode":"const overrideIds = new Map(assignments.map(a => [a.id, a.assignment_overrides.map(o => o.id)]));\nfor (const [aid, entries] of payload)\n  for (const e of entries)\n    if (!overrideIds.get(aid)?.includes(e.id)) throw new Error(`override ${e.id} not on assignment ${aid}`);","typeGuard":"const overrideOnAssignment = (overrideId, assignment) =>\n  assignment.assignment_overrides.some(o => o.id === overrideId)","tryCatchPattern":"begin\n  Assignment::BulkUpdate.new(course, user, payload).run\nrescue ActiveRecord::RecordNotFound => e\n  render json: { error: e.message }, status: :not_found\nend","preventionTips":["Reload assignment_overrides right before bulk updates to drop deleted overrides","Key override entries under their correct assignment in the payload","Listen for override deletion events and refresh stale UI state"],"tags":["activerecord","bulk-update","record-not-found"],"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"}