instructure/canvas-lms · warning · ConversationsHelper::RepliesLockedForUser

Unauthorized, unable to add messages to conversation

Error message

Unauthorized, unable to add messages to conversation

What it means

process_response in ConversationsHelper validates that the current user may add a message to the conversation. ConversationsHelper::RepliesLockedForUser (a subclass of Error) is raised with status :unauthorized when replies are locked for the user for the given recipients, preventing automated/manual message adds to a locked conversation.

Solutions

  1. Check replies_locked_for? before attempting to add the message and skip gracefully
  2. Verify the current_user is an active participant of the conversation
  3. If automation (e.g. out-of-office responses), rescue ConversationsHelper::RepliesLockedForUser and log instead of failing the job
  4. Restore the user's participation or use a conversation that is not locked

Example fix

// before
add_message(conversation, ...)
// after
unless conversation.conversation.replies_locked_for?(current_user, recipients)
  add_message(conversation, ...)
end
Defensive patterns

Strategy: try-catch

Validate before calling

locked = conversation.conversation.replies_locked_for?(current_user, recipients)
render json: { errors: ['replies locked'] }, status: :unauthorized if locked

Try / catch

begin
  process_response(...)
rescue ConversationsHelper::RepliesLockedForUser => e
  render json: { error: e.message }, status: :unauthorized
end

Prevention

When it happens

Trigger: Calling process_response (directly or via trigger_out_of_office_auto_responses) on a conversation whose conversation#replies_locked_for?(current_user, recipients) is true — e.g. the conversation was locked/retired or the user lost participation rights.

Common situations: Automated out-of-office reply jobs firing for conversations where the user can no longer reply; a user replying in the UI after an admin locked the thread; sending messages to a conversation after being removed as a participant.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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

Appendix: source

Thrown at app/helpers/conversations_helper.rb:37

module ConversationsHelper
  def process_response(
    conversation:,
    context:,
    current_user:,
    session:,
    recipients:,
    context_code:,
    message_ids:,
    body:,
    attachment_ids:,
    domain_root_account_id:,
    media_comment_id:,
    media_comment_type:,
    automated: false
  )
    if conversation.conversation.replies_locked_for?(current_user, recipients)
      raise ConversationsHelper::RepliesLockedForUser.new(message: I18n.t("Unauthorized, unable to add messages to conversation"), status: :unauthorized, attribute: "workflow_state")
    end

    if context.is_a?(Course) && context.workflow_state == "completed" && !context.grants_right?(current_user, session, :read_as_admin)
      raise ConversationsHelper::Error.new(message: I18n.t("Course concluded, unable to send messages"), status: :unauthorized, attribute: "workflow_state")
    end

    if body.blank?
      raise ConversationsHelper::Error.new(message: I18n.t("Unable to create message without a body"), status: :bad_request, attribute: "empty_message")
    end

    recipients = normalize_recipients(
      recipients:,
      context_code:,
      conversation_id: conversation.conversation_id,
      current_user:,
      session:
    )

View on GitHub (pinned to 1c9f0bb801)