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
- Confirm the current user (or participant_id) belongs to the appointment group's possible_participants
- If passing participant_id with manage rights, use an id from the appointment group's possible_participants
- Add the user/group/section as a participant of the appointment group before reserving
- 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
- Fetch possible_participants before reserving with a managed participant_id
- Keep group/section membership current before appointment signups
- Never pass a participant_id for a user outside the appointment group
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
- Failed updating an event in the series, update not saved
- ineligible participant
- not an appointment
- all slots filled
- cannot cancel past reservation
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
endView on GitHub (pinned to 1c9f0bb801)