instructure/canvas-lms · error · ActiveRecord::Rollback

Failed updating an event in the series, update not saved

Error message

Failed updating an event in the series, update not saved

What it means

In CalendarEventsApiController#destroy_from_series, when deleting/updating one event in a recurring (rrule) series, each front-half sibling event must both be permitted (grants_any_right? :update) and save successfully with the new rrule params. Any failure sets an error hash with message 'Failed updating an event in the series, update not saved' (401 for permission, generic otherwise) and raises ActiveRecord::Rollback, aborting the whole transaction so no partial update persists.

Solutions

  1. Ensure the acting user has :update rights on every event in the series (manage all calendars involved), or delete only occurrences they own
  2. Inspect the failing event's validation errors (event.errors) and fix the underlying validation problem
  3. Retry after concurrent-modification conflicts, re-reading the series events
  4. As an admin, operate as the series owner or use site-admin privileges

Example fix

// before
event.update(params_for_update_front_half) # fails validation, silent rollback
// after
unless event.update(params_for_update_front_half)
  Rails.logger.warn("series event #{event.id}: #{event.errors.full_messages}")
  error = { message: event.errors.full_messages.to_sentence }
  raise ActiveRecord::Rollback
end
Defensive patterns

Strategy: try-catch

Validate before calling

// Ruby pre-check before series operations
unless series_events.all? { |e| e.grants_any_right?(user, session, :update) }
  raise PermissionDenied, 'user cannot update all events in the series'
end

Try / catch

begin
  destroy_from_series(event)
rescue ActiveRecord::Rollback
  # whole series update aborted; inspect error hash / event.errors, reload, then retry
end

Prevention

When it happens

Trigger: DELETE/update on a series event where at least one sibling event in the series is owned by/visible to a user lacking :update permission, or an event.update fails validation (e.g. invalid rrule count/until params, locked events, or concurrent modification).

Common situations: A user deletes their own occurrence of a shared series they don't fully manage; series containing events across contexts with differing permissions; validation failures from recomputed rrule count/until; stale events deleted concurrently by another user.

Related errors


AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15). Data as JSON: /api/errors/bc9699e0586c5506. Report an issue: GitHub.

Appendix: source

Thrown at app/controllers/calendar_events_api_controller.rb:910

            if event.appointment_group && @event.appointment_group.appointments.count == 0
              event.appointment_group.destroy(@current_user)
            end
          else
            error = event.errors
            raise ActiveRecord::Rollback
          end
        end

        if params[:which] == "following"
          # the remaining series just got shorter. reflect that in the rrrule
          front_half_events = (find_which_series_events(target_event: @event, which: "all", for_update: false) - events).to_a
          unless front_half_events.empty?
            params_for_update_front_half = ActionController::Parameters.new(rrule: update_rrule_count_or_until(@event[:rrule], front_half_events.length)).permit(:rrule)
            front_half_events.each do |event|
              event.updating_user = @current_user
              unless event.grants_any_right?(@current_user, session, :update)
                error = { message: t("Failed updating an event in the series, update not saved"), status: :unauthorized }
                raise ActiveRecord::Rollback
              end

              unless event.update(params_for_update_front_half)
                error = { message: t("Failed updating an event in the series, update not saved") }
                raise ActiveRecord::Rollback
              end
            end
          end
        end
      end
    end

    return render json: error, status: :bad_request if error

    @event.context.touch # assume all events in the series belong to the same context

    json = (events + front_half_events).map do |event|
      event.reload

View on GitHub (pinned to 1c9f0bb801)