instructure/canvas-lms · error · InsufficientPermissionsError

Insufficient Permissions

Error message

Insufficient Permissions

What it means

build_entry raises the custom InsufficientPermissionsError when the freshly built DiscussionEntry does not grant :create to the current user (entry.grants_right?). resolve rescues it and converts it to a GraphQL validation error with message "Insufficient Permissions". This is a policy failure, not a data failure: records exist but the user may not post.

Solutions

  1. Check the topic's locked/available state (locked_for_user, available_from/until) before rendering the reply editor.
  2. Verify the user's enrollment and that the topic grants :create via the discussionTopic.permissions GraphQL field.
  3. Unlock the topic or adjust the user's role/permissions if posting should be allowed.
  4. Hide the reply UI when entryPermissions.create is false so users never hit the error.

Example fix

// before: always show reply box
<ReplyForm topicId={topic.id} />

// after
{topic.permissions.create && <ReplyForm topicId={topic.id} />}
Defensive patterns

Strategy: validation

Validate before calling

const canCreate = topic.permissions?.create
if (!canCreate) { disableReplyEditor(); return }
if (topic.lockedForUser || isPast(topic.lockDate)) { showLockedNotice(); return }

Type guard

const canPost = (topic) => Boolean(topic?.permissions?.create)

Prevention

When it happens

Trigger: A student replying to a locked/closed-for-comments topic; posting to an anonymous or read-only discussion without :create rights; a user whose enrollment is concluded or who is not enrolled trying to reply; topic locked until a future date.

Common situations: UI not honoring locked_until / closed_for_comments state; group discussions where the user is not in the group; teachers impersonating or masquerading with reduced rights; account-level discussions with restricted posting roles.

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/5496856cdd932fef. Report an issue: GitHub.

Appendix: source

Thrown at app/graphql/mutations/create_discussion_entry.rb:93

    obj = { discussion_entry: entry, my_sub_assignment_submissions: [] }

    if has_sub_assignment_submissions?(current_user, topic)
      checkpoint_submissions = topic.assignment&.sub_assignment_submissions&.active&.where(user_id: current_user)
      obj[:my_sub_assignment_submissions] = checkpoint_submissions
    end

    obj
  rescue ActiveRecord::RecordNotFound
    raise GraphQL::ExecutionError, "not found"
  rescue InsufficientPermissionsError
    validation_error(I18n.t("Insufficient Permissions"))
  end

  def build_entry(association, message, topic, is_anonymous_author)
    message = Api::Html::Content.process_incoming(message, host: context[:request].host, port: context[:request].port)
    entry = association.build(message:, user: current_user, discussion_topic: topic, is_anonymous_author:)
    raise InsufficientPermissionsError unless entry.grants_right?(current_user, session, :create)

    entry
  end

  def has_sub_assignment_submissions?(current_user, topic)
    # if group discussion context is not a course, then there will be no assignment nor submissions
    return false if topic.context.is_a?(Group) && !topic.context.context.is_a?(Course)

    course_id = topic.context.is_a?(Course) ? topic.context.id : topic.context.context.id

    # for graded group discussions, .assignment for the root topic and for each child topic is the same
    # assignment
    topic.assignment&.reload&.has_sub_assignments? && current_user.student_enrollments.where(course_id:).exists?
  end

  class InsufficientPermissionsError < StandardError; end
end

View on GitHub (pinned to 1c9f0bb801)