instructure/canvas-lms · error · ActiveRecord::RecordNotFound
invalid assignment override id #
Error message
invalid assignment override id #{override_data["id"]} for assignment #{assignment.id} What it means
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.
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
Example fix
// before
overrides.each { |o| run_entry(assignment, o) } # may reference stale ids
// after
valid = assignment.assignment_overrides.reload.map(&:id)
overrides.select { |o| valid.include?(o["id"].to_i) }.each { |o| run_entry(assignment, o) } Defensive patterns
Strategy: try-catch
Validate before calling
const overrideIds = new Map(assignments.map(a => [a.id, a.assignment_overrides.map(o => o.id)]));
for (const [aid, entries] of payload)
for (const e of entries)
if (!overrideIds.get(aid)?.includes(e.id)) throw new Error(`override ${e.id} not on assignment ${aid}`); Type guard
const overrideOnAssignment = (overrideId, assignment) => assignment.assignment_overrides.some(o => o.id === overrideId)
Try / catch
begin
Assignment::BulkUpdate.new(course, user, payload).run
rescue ActiveRecord::RecordNotFound => e
render json: { error: e.message }, status: :not_found
end Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- invalid assignment id #
- # not found
- not found
- Resource not found for type: #
- A course did not pass validation
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/f8eb490539ceac20.
Report an issue: GitHub.
Appendix: source
Thrown at app/models/assignment/bulk_update.rb:57
next unless dates.present?
base, overrides = dates.partition { |date| date["base"] }
# 1a. update the assignment
assignment = assignments[id.to_i]
raise ActiveRecord::RecordNotFound, "invalid assignment id #{id}" unless assignment
if base.any?
assignment.content_being_saved_by(@current_user)
assignment.updating_user = @current_user
assignment.assign_attributes(base.first.slice(*%w[due_at unlock_at lock_at]))
assignments_to_save << assignment if assignment.changed?
end
# 1b. update associated overrides
overrides.each do |override_data|
override = assignment.assignment_overrides.detect { |o| o.id == override_data["id"].to_i }
raise ActiveRecord::RecordNotFound, "invalid assignment override id #{override_data["id"]} for assignment #{assignment.id}" unless override
%w[due_at unlock_at lock_at].each do |date|
if override_data.key?(date)
override.send(:"#{date}=", override_data[date])
override.send(:"#{date}_overridden=", true)
else
override.send(:"#{date}=", nil)
override.send(:"#{date}_overridden=", false)
end
end
assignments_to_save << assignment if override.changed?
end
end
progress_count = 0
progress_total = assignments_to_save.size * 2
# 2. validate all assignments and overridesView on GitHub (pinned to 1c9f0bb801)