instructure/canvas-lms · error · GraphQL::ExecutionError

insufficient permission

Error message

insufficient permission

What it means

CreateLearningOutcome#check_permission raises 'insufficient permission' when outcome.grants_right?(current_user, :create) is false. The outcome is built in the target group's context, so the caller must have the :create right (typically manage-outcomes related) in that course/account.

Solutions

  1. Use a token/user with :create rights in the outcome group's context (account admin with manage outcomes, or permissive course role).
  2. Check the context's role overrides for the user's role to confirm :create outcome rights.
  3. Pick a group in a context where the user does have permission.
  4. Catch GraphQL errors with message 'insufficient permission' client-side and surface a permission UI state.

Example fix

// before
const res = await gql(createLearningOutcomeMutation, { input })
// after
const canCreate = await gql(checkOutcomePermissionQuery, { contextId })
if (!canCreate) throw new UserFacingError('You need outcome-creation rights')
const res = await gql(createLearningOutcomeMutation, { input })
Defensive patterns

Strategy: validation

Validate before calling

const perms = await gql(CONTEXT_PERMISSIONS, { contextId, contextType })
if (!perms.createOutcome) throw new Error('user lacks :create on outcome context')

Try / catch

try {
  await gql(CREATE_OUTCOME, { input })
} catch (e) {
  if (e.message === 'insufficient permission') renderPermissionDenied()
  else throw e
}

Prevention

When it happens

Trigger: Calling createLearningOutcome as a user without :create rights on the outcome's context — e.g. a student, a teacher in a course where outcome management is account-level only, or an admin on a sub-account without outcome permissions.

Common situations: Autonomous agents using a teacher token when outcomes are restricted to account admins; role overrides removed :create for teachers; cross-account group where the user has rights in one account but not the group's.

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/06bf92b115b18539. Report an issue: GitHub.

Appendix: source

Thrown at app/graphql/mutations/create_learning_outcome.rb:49

    record = LearningOutcome.new(context: outcome_group.context, **outcome_input)
    record.saving_user = current_user
    check_permission(record)
    return errors_for(record) unless record.save

    outcome_group.add_outcome(record)
    { learning_outcome: record }
  end

  private

  def learning_outcome_group(input)
    LearningOutcomeGroup.active.find_by(id: input[:group_id]).tap do |group|
      raise GraphQL::ExecutionError, I18n.t("group not found") if group.nil?
    end
  end

  def check_permission(outcome)
    raise GraphQL::ExecutionError, I18n.t("insufficient permission") unless outcome.grants_right? current_user, :create
  end
end

View on GitHub (pinned to 1c9f0bb801)