{"record":{"id":"083fe5253d7416ba","repo":"instructure/canvas-lms","slug":"invalid-participant","errorCode":null,"errorMessage":"invalid participant","messagePattern":"invalid participant","errorType":"exception","errorClass":"CalendarEvent::ReservationError","httpStatus":400,"severity":"error","filePath":"app/controllers/calendar_events_api_controller.rb","lineNumber":692,"sourceCode":"  #\n  #   curl 'https://<canvas>/api/v1/calendar_events/345/reservations.json' \\\n  #        -X POST \\\n  #        -F 'cancel_existing=true' \\\n  #        -H \"Authorization: Bearer <token>\"\n  def reserve\n    get_event\n    @request_shard = Shard.current\n    @event.shard.activate do\n      if authorized_action(@event, @current_user, :reserve) && check_for_past_signup(@event)\n        begin\n          participant_id = Shard.relative_id_for(params[:participant_id], @request_shard, Shard.current) if params[:participant_id]\n          if participant_id && @event.appointment_group.grants_right?(@current_user, session, :manage)\n            participant = @event.appointment_group.possible_participants.detect { |p| p.id == participant_id }\n          else\n            participant = @event.appointment_group.participant_for(@current_user)\n            participant = nil if participant && participant_id && participant_id != participant.id\n          end\n          raise CalendarEvent::ReservationError, \"invalid participant\" unless participant\n\n          reservation = @event.reserve_for(participant,\n                                           @current_user,\n                                           cancel_existing: value_to_boolean(params[:cancel_existing]),\n                                           comments: params[\"comments\"])\n          render json: event_json(reservation, @current_user, session, request_shard: @request_shard)\n        rescue CalendarEvent::ReservationError => e\n          reservations = participant ? @event.appointment_group.reservations_for(participant) : []\n          render json: [{\n            attribute: \"reservation\",\n            type: \"calendar_event\",\n            message: e.message,\n            reservations: reservations.map { |r| event_json(r, @current_user, session, request_shard: @request_shard) }\n          }],\n                 status: :bad_request\n        end\n      end\n    end","sourceCodeStart":674,"sourceCodeEnd":710,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/controllers/calendar_events_api_controller.rb#L674-L710","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nparticipant_id = user.id # user not in group's possible participants\n// after\nparticipant = group.possible_participants.detect { |p| p.id == user.id }\nraise CalendarEvent::ReservationError, 'invalid participant' unless participant\nparticipant_id = participant.id","handlingStrategy":"validation","validationCode":"const group = await api.get(`/api/v1/appointment_groups/${groupId}`)\nconst eligible = group.participants?.some(p => p.id === userId)\nif (!eligible) throw new Error('user is not a possible participant')","typeGuard":"function isEligibleParticipant(group, userId) { return Array.isArray(group.participants) && group.participants.some(p => p.id === userId) }","tryCatchPattern":"try { await reserveSlot(eventId) } catch (e) { if (/invalid participant/.test(e.message)) refreshGroupMembership(); else throw e }","preventionTips":["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"],"tags":["rails","api","calendar","appointments"],"backgroundTag":"invalid-argument-value","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"}