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

insufficient permission

Error message

insufficient permission

What it means

updateInternalSetting raises this GraphQL::ExecutionError when the caller lacks :manage_internal_settings on Account.site_admin OR the targeted Setting is marked secret. Internal settings are site-admin-only; even site admins may not read/modify settings flagged secret through this mutation.

Solutions

  1. Confirm the user has :manage_internal_settings on Account.site_admin (root Site Admin account), granting via site admin role if needed.
  2. If the setting is secret, modify it out-of-band (Rails console with Setting.set, or the config mechanism that owns it) — the GraphQL mutation will always refuse.
  3. Double-check the internal_setting_id resolves to the intended Setting and is not unexpectedly marked secret.

Example fix

// Rails console
# before: denied via mutation for a secret setting
# after: set directly
Account.site_admin.grants_right?(user, :manage_internal_settings) # => true
Setting.set(setting_name, "new_value")
Defensive patterns

Strategy: validation

Validate before calling

// Rails console pre-check
raise 'not a site admin' unless Account.site_admin.grants_right?(current_user, :manage_internal_settings)

Type guard

function isSiteAdminWithInternalSettings(viewer) { return viewer?.permissions?.includes('manage_internal_settings') ?? false }

Try / catch

try {
  await updateInternalSetting({ variables: { input } })
} catch (e) {
  if (e.graphQLErrors?.some(g => g.message === 'insufficient permission')) {
    // fall back to Rails console / config pipeline for secret settings
  } else throw e
}

Prevention

When it happens

Trigger: Calling updateInternalSetting as a non-site-admin user; or as a site admin when Setting.find(input[:internal_setting_id]).secret returns true — the combined condition in the single if-statement raises for either case, so a secret setting yields 'insufficient permission' even for authorized admins.

Common situations: Using a regular account-admin token for a site-level setting, attempting to edit a secret setting (e.g. encrypted credentials-backed) that Canvas deliberately shields, or a typo'd/ambiguous ID resolving to the wrong Setting record.

Understand the failure class

Background: "You do not have permission" / 403 Forbidden errors: authenticated but not allowed — causes and fixes across open-source libraries — this error's family across 31 libraries.

Related errors


AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15). Data as JSON: /api/errors/3c57cc66639fbe05. Report an issue: GitHub.

Appendix: source

Thrown at app/graphql/mutations/update_internal_setting.rb:28

#
# 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::UpdateInternalSetting < Mutations::BaseMutation
  graphql_name "UpdateInternalSetting"

  argument :internal_setting_id, ID, required: true, prepare: GraphQLHelpers.relay_or_legacy_id_prepare_func("InternalSetting")
  argument :value, String, required: true

  field :internal_setting, Types::InternalSettingType, null: false
  def resolve(input:)
    if !Account.site_admin.grants_right?(current_user, :manage_internal_settings) || (internal_setting = Setting.find(input[:internal_setting_id])).secret
      raise GraphQL::ExecutionError, "insufficient permission"
    end

    unless input[:value].nil?
      Setting.set(internal_setting.name, input[:value])
      internal_setting.reload
    end

    {
      internal_setting:
    }
  rescue ActiveRecord::RecordNotFound
    raise GraphQL::ExecutionError, "not found"
  end
end

View on GitHub (pinned to 1c9f0bb801)