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

insufficient permission

Error message

insufficient permission

What it means

GraphQL mutation CreateInternalSetting raises GraphQL::ExecutionError in resolve() when the current user lacks the :manage_internal_settings right on the site-admin Account. Internal settings are global Setting key/value pairs, so only site admins may write them. The check runs before Setting.set is called, so no write occurs on failure.

Solutions

  1. Perform the mutation as a user with site-admin membership on Account.site_admin (grant :manage_internal_settings).
  2. Verify the bearer token / session actually resolves to that site-admin user, not an masquerade or expired session.
  3. If the user should have access, add the correct role/permission via the site admin account or console: account.role_overrides or direct site-admin admin enrollment.
  4. Handle the error client-side by checking permissions before exposing the mutation in the UI.

Example fix

// before
Setting.set(input[:name], input[:value]) // raises for non site-admins
// after
context[:site_admin_granted] = Account.site_admin.grants_right?(current_user, :manage_internal_settings)
raise GraphQL::ExecutionError, 'insufficient permission' unless context[:site_admin_granted]
Setting.set(input[:name], input[:value])
Defensive patterns

Strategy: validation

Validate before calling

// GraphQL: check permissions on the viewer before mutating
const viewer = await gql(GET_VIEWER, { id })
if (!viewer.siteAdmin || !viewer.permissions.manageInternalSettings) throw new Error('requires site admin with manage_internal_settings')

Try / catch

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

Prevention

When it happens

Trigger: Calling mutation createInternalSetting(name:, value:) as a user whose effective roles on Account.site_admin do not grant :manage_internal_settings — e.g. a root-account admin (not site admin), a teacher, or an anonymous/unauthenticated request.

Common situations: Deploying a tool that assumes account-level admins can set internal settings; running the mutation against a non-production shard where the user's site-admin membership was not seeded; testing with a token minted for a regular admin.

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/9521c1878287ca0b. Report an issue: GitHub.

Appendix: source

Thrown at app/graphql/mutations/create_internal_setting.rb:29

#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
class Mutations::CreateInternalSetting < Mutations::BaseMutation
  graphql_name "CreateInternalSetting"

  argument :name, String, required: true
  argument :value, String, required: true

  field :internal_setting, Types::InternalSettingType, null: true
  def resolve(input:)
    unless Account.site_admin.grants_right?(current_user, :manage_internal_settings)
      raise GraphQL::ExecutionError, "insufficient permission"
    end

    Setting.set(input[:name], input[:value])
    internal_setting = Setting.find_by!(name: input[:name])

    { internal_setting: }
  rescue ActiveRecord::RecordInvalid => e
    errors_for(e.record)
  end
end

View on GitHub (pinned to 1c9f0bb801)