{"record":{"id":"01064406979c97e0","repo":"instructure/canvas-lms","slug":"unauthorized-unable-to-add-messages-to-conversation","errorCode":null,"errorMessage":"Unauthorized, unable to add messages to conversation","messagePattern":"Unauthorized, unable to add messages to conversation","errorType":"exception","errorClass":"ConversationsHelper::RepliesLockedForUser","httpStatus":401,"severity":"warning","filePath":"app/helpers/conversations_helper.rb","lineNumber":37,"sourceCode":"\nmodule ConversationsHelper\n  def process_response(\n    conversation:,\n    context:,\n    current_user:,\n    session:,\n    recipients:,\n    context_code:,\n    message_ids:,\n    body:,\n    attachment_ids:,\n    domain_root_account_id:,\n    media_comment_id:,\n    media_comment_type:,\n    automated: false\n  )\n    if conversation.conversation.replies_locked_for?(current_user, recipients)\n      raise ConversationsHelper::RepliesLockedForUser.new(message: I18n.t(\"Unauthorized, unable to add messages to conversation\"), status: :unauthorized, attribute: \"workflow_state\")\n    end\n\n    if context.is_a?(Course) && context.workflow_state == \"completed\" && !context.grants_right?(current_user, session, :read_as_admin)\n      raise ConversationsHelper::Error.new(message: I18n.t(\"Course concluded, unable to send messages\"), status: :unauthorized, attribute: \"workflow_state\")\n    end\n\n    if body.blank?\n      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","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/helpers/conversations_helper.rb#L19-L55","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check replies_locked_for? before attempting to add the message and skip gracefully","Verify the current_user is an active participant of the conversation","If automation (e.g. out-of-office responses), rescue ConversationsHelper::RepliesLockedForUser and log instead of failing the job","Restore the user's participation or use a conversation that is not locked"],"exampleFix":"// before\nadd_message(conversation, ...)\n// after\nunless conversation.conversation.replies_locked_for?(current_user, recipients)\n  add_message(conversation, ...)\nend","handlingStrategy":"try-catch","validationCode":"locked = conversation.conversation.replies_locked_for?(current_user, recipients)\nrender json: { errors: ['replies locked'] }, status: :unauthorized if locked","typeGuard":null,"tryCatchPattern":"begin\n  process_response(...)\nrescue ConversationsHelper::RepliesLockedForUser => e\n  render json: { error: e.message }, status: :unauthorized\nend","preventionTips":["Check replies_locked_for? before attempting sends","In background jobs, rescue and log instead of crashing","Verify user participation before composing replies"],"tags":["conversations","authorization","ruby"],"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"}