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

not authorized

Error message

not authorized

What it means

Raised when the current user does not have the `manage_institutional_tags_edit` right on the root account. The mutation checks permissions via `root_account.grants_right?(current_user, session, :manage_institutional_tags_edit)` before touching any data.

Solutions

  1. Grant the managing user the `manage_institutional_tags_edit` right via the account's role permissions (Admin > Permissions).
  2. Confirm you are authenticated as the intended admin (check current_user/context in the GraphQL request).
  3. If testing, create an account admin: `account.account_users.create!(user:)` or stub `grants_right?`.
  4. Verify the custom role on that specific root account includes the institutional tag permissions.

Example fix

// before
# mutation called as a user without the right -> 'not authorized'

// after: ensure caller has the permission
account.account_users.create!(user: admin_user)
RoleOverride.create!(role: admin_role, permission: 'manage_institutional_tags_edit', enabled: true)
Defensive patterns

Strategy: validation

Validate before calling

unless root_account.grants_right?(current_user, session, :manage_institutional_tags_edit)
  raise 'caller lacks manage_institutional_tags_edit'
end

Try / catch

begin
  result = apply_tag(input)
rescue GraphQL::ExecutionError => e
  handle_unauthorized if e.message == 'not authorized'
end

Prevention

When it happens

Trigger: Calling applyInstitutionalTag as a student, teacher, or admin whose role lacks :manage_institutional_tags_edit; an unauthenticated request (current_user nil); session expired so grants_right? evaluates against nil user.

Common situations: Custom role without the institutional-tag permission enabled; user logged into a different account/shard; API token belonging to a non-admin user; testing as a user who was recently demoted and cached rights are stale.

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/71ea9defa162a969. Report an issue: GitHub.

Appendix: source

Thrown at app/graphql/mutations/apply_institutional_tag.rb:39

# NOTE: Depends on InstitutionalTag, InstitutionalTagAssociation models

module Mutations
  class ApplyInstitutionalTag < BaseMutation
    argument :tag_id,
             ID,
             required: true,
             prepare: GraphQLHelpers.relay_or_legacy_id_prepare_func("InstitutionalTag")
    argument :user_id,
             ID,
             required: true,
             prepare: GraphQLHelpers.relay_or_legacy_id_prepare_func("User")

    field :institutional_tag_association, Types::InstitutionalTagAssociationType, null: true

    def resolve(input:) # rubocop:disable GraphQL/UnusedArgument
      root_account = context[:domain_root_account]
      raise GraphQL::ExecutionError, "feature flag is disabled" unless root_account.feature_enabled?(:institutional_tags)
      raise GraphQL::ExecutionError, "not authorized" unless root_account.grants_right?(current_user, session, :manage_institutional_tags_edit)

      tag = InstitutionalTag.where(root_account_id: root_account.id, workflow_state: "active").find_by(id: input[:tag_id])
      raise GraphQL::ExecutionError, "not found" unless tag

      user = root_account.all_users.find_by(id: input[:user_id])
      raise GraphQL::ExecutionError, "not found" unless user

      assoc = InstitutionalTagAssociation.find_or_initialize_by(
        institutional_tag: tag,
        context: user,
        root_account:
      )
      assoc.workflow_state = "active"

      if assoc.save
        { institutional_tag_association: assoc }
      else
        errors_for(assoc)

View on GitHub (pinned to 1c9f0bb801)