instructure/canvas-lms · error · CalendarEvent::ReservationError

invalid participant

Error message

invalid participant

What it means

In CalendarEventsApiController#reserve, after determining the participant for an appointment reservation (either a managed participant_id matched against possible_participants, or participant_for(@current_user)), the code raises CalendarEvent::ReservationError 'invalid participant' when no participant could be resolved. This surfaces as an API error for the appointment reservation endpoint.

Solutions

  1. Confirm the current user (or participant_id) belongs to the appointment group's possible_participants
  2. If passing participant_id with manage rights, use an id from the appointment group's possible_participants
  3. Add the user/group/section as a participant of the appointment group before reserving
  4. Re-fetch the appointment group after membership changes so ids are current

Example fix

// before
participant_id = user.id # user not in group's possible participants
// after
participant = group.possible_participants.detect { |p| p.id == user.id }
raise CalendarEvent::ReservationError, 'invalid participant' unless participant
participant_id = participant.id
Defensive patterns

Strategy: validation

Validate before calling

const group = await api.get(`/api/v1/appointment_groups/${groupId}`)
const eligible = group.participants?.some(p => p.id === userId)
if (!eligible) throw new Error('user is not a possible participant')

Type guard

function isEligibleParticipant(group, userId) { return Array.isArray(group.participants) && group.participants.some(p => p.id === userId) }

Try / catch

try { await reserveSlot(eventId) } catch (e) { if (/invalid participant/.test(e.message)) refreshGroupMembership(); else throw e }

Prevention

When it happens

Trigger: POST to reserve a calendar event slot where: the user is not a possible participant of the appointment_group; a manager-supplied participant_id doesn't match any possible_participants id; or the passed participant_id doesn't match the current user's own participant record.

Common situations: Students trying to reserve in a group where they are not a member of a participating group/section; admin/tool automation passing user ids that aren't in the appointment group's participant set; cross-section or cross-course users; stale ids after group membership changed.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at app/controllers/calendar_events_api_controller.rb:692

  #
  #   curl 'https://<canvas>/api/v1/calendar_events/345/reservations.json' \
  #        -X POST \
  #        -F 'cancel_existing=true' \
  #        -H "Authorization: Bearer <token>"
  def reserve
    get_event
    @request_shard = Shard.current
    @event.shard.activate do
      if authorized_action(@event, @current_user, :reserve) && check_for_past_signup(@event)
        begin
          participant_id = Shard.relative_id_for(params[:participant_id], @request_shard, Shard.current) if params[:participant_id]
          if participant_id && @event.appointment_group.grants_right?(@current_user, session, :manage)
            participant = @event.appointment_group.possible_participants.detect { |p| p.id == participant_id }
          else
            participant = @event.appointment_group.participant_for(@current_user)
            participant = nil if participant && participant_id && participant_id != participant.id
          end
          raise CalendarEvent::ReservationError, "invalid participant" unless participant

          reservation = @event.reserve_for(participant,
                                           @current_user,
                                           cancel_existing: value_to_boolean(params[:cancel_existing]),
                                           comments: params["comments"])
          render json: event_json(reservation, @current_user, session, request_shard: @request_shard)
        rescue CalendarEvent::ReservationError => e
          reservations = participant ? @event.appointment_group.reservations_for(participant) : []
          render json: [{
            attribute: "reservation",
            type: "calendar_event",
            message: e.message,
            reservations: reservations.map { |r| event_json(r, @current_user, session, request_shard: @request_shard) }
          }],
                 status: :bad_request
        end
      end
    end

View on GitHub (pinned to 1c9f0bb801)