{"record":{"id":"1dae0321244f6e04","repo":"instructure/canvas-lms","slug":"the-following-recipients-have-no-active-enrollment-in-the","errorCode":null,"errorMessage":"The following recipients have no active enrollment in the course, %{invalid_recipients}, unable to send messages","messagePattern":"The following recipients have no active enrollment in the course, %(.+?), unable to send messages","errorType":"exception","errorClass":"ConversationsHelper::Error","httpStatus":401,"severity":"error","filePath":"app/helpers/conversations_helper.rb","lineNumber":63,"sourceCode":"      raise ConversationsHelper::Error.new(message: I18n.t(\"Unable to create message without a body\"), status: :bad_request, attribute: \"empty_message\")\n    end\n\n    recipients = normalize_recipients(\n      recipients:,\n      context_code:,\n      conversation_id: conversation.conversation_id,\n      current_user:,\n      session:\n    )\n\n    if recipients && !conversation.conversation.can_add_participants?(recipients)\n      raise ConversationsHelper::Error.new(message: I18n.t(\"Too many participants for group conversation\"), status: :bad_request, attribute: \"recipients\")\n    end\n\n    invalid_recipients = get_invalid_recipients(context, recipients, current_user)\n    unless invalid_recipients.to_a.empty?\n      invalid_recipients = invalid_recipients.pluck(1)\n      raise ConversationsHelper::Error.new(message: I18n.t(\"The following recipients have no active enrollment in the course, %{invalid_recipients}, unable to send messages\", invalid_recipients:), status: :unauthorized, attribute: \"recipients\")\n    end\n\n    tags = infer_tags(\n      recipients: conversation.conversation.participants.pluck(:id),\n      context_code:\n    )\n\n    validate_message_ids(message_ids, conversation, current_user:)\n    message_args = build_message_args(\n      body:,\n      attachment_ids:,\n      domain_root_account_id:,\n      media_comment_id:,\n      media_comment_type:,\n      current_user:,\n      automated:\n    )\n","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/helpers/conversations_helper.rb#L45-L81","documentation":"ConversationsHelper raises this ConversationsHelper::Error when validating recipients for a course-context conversation: one or more recipients lack an active enrollment in the course. The guard exists to prevent messaging users who are not currently enrolled, leaking or failing on stale recipient lists.","triggerScenarios":"POST to the conversations API with context = a course and recipients whose enrollments are completed, deleted, invited-but-not-active, or whose enrollment was conclude/soft-deleted after the recipient list was cached.","commonSituations":"Sending to a course section roster after term conclusion; messaging users imported via SIS whose enrollment sync has not run; stale client-side autocomplete lists; users who dropped the course between drafting and sending.","solutions":["Filter recipients to users with an active enrollment in the context before sending (e.g. course.enrollments.active.where(user_id:) map).","Refresh the recipient list from the API (GET /api/v1/courses/:id/enrollments) instead of a cached roster.","If recipients should be valid, fix enrollment data: re-run SIS import or reinstate the enrollment.","Catch ConversationsHelper::Error and surface the invalid_recipients names to the sender so they can deselect them."],"exampleFix":"// before\n@conversation = create_conversation(..., recipients: params[:recipients])\n// after\ninvalid = ConversationsHelper.get_invalid_recipients(course, params[:recipients], current_user)\nparams[:recipients] = params[:recipients] - invalid.pluck(1)\nraise if params[:recipients].empty?\n@conversation = create_conversation(..., recipients: params[:recipients])","handlingStrategy":"validation","validationCode":"active_ids = course.enrollments.active.pluck(:user_id)\nbad = recipients - active_ids.map(&:to_s)\nraise ArgumentError, \"not enrolled: #{bad.join(',')}\" if bad.any?","typeGuard":"def active_enrolled?(course, user_id)\n  course.enrollments.active.exists?(user_id: user_id)\nend","tryCatchPattern":"begin\n  send_conversation(...)\nrescue ConversationsHelper::Error => e\n  render json: { errors: [{ attribute: e.attribute, message: e.message }] }, status: e.status\nend","preventionTips":["Always resolve recipients from the live enrollment API, not cached rosters","Re-check enrollments right before bulk sends","Surface invalid recipient names to the UI instead of failing silently"],"tags":["conversations","enrollment","validation"],"backgroundTag":"permission-denied","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"}