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

insufficient permission

Error message

insufficient permission

What it means

The deleteInternalSetting mutation raises "insufficient permission" when the caller is not a site admin with :manage_internal_settings rights, OR when the targeted Setting is marked secret. Both conditions are collapsed into a single error by design to avoid leaking information about secret settings.

Solutions

  1. Authenticate as a site admin (Account.site_admin) with :manage_internal_settings permission
  2. Check the setting is not secret via Setting before attempting deletion
  3. Verify the user's role overrides at the site-admin account level
  4. If the setting is secret, manage it through console/Setting API instead

Example fix

// before
Setting.remove(input[:internal_setting_id])
// after
raise GraphQL::ExecutionError, "insufficient permission" unless Account.site_admin.grants_right?(current_user, :manage_internal_settings)
setting = Setting.find(input[:internal_setting_id])
raise GraphQL::ExecutionError, "insufficient permission" if setting.secret
Defensive patterns

Strategy: try-catch

Validate before calling

const isSiteAdmin = await query(myPermissions, { accountId: "site_admin" });
if (!isSiteAdmin?.manageInternalSettings) return skip();

Type guard

function hasInternalSettingsAccess(perms) {
  return perms?.manageInternalSettings === true;
}

Try / catch

try {
  await client.mutate(DELETE_INTERNAL_SETTING, { internalSettingId });
} catch (e) {
  if (e.message === "insufficient permission") {
    // escalate token or skip secret settings
  } else throw e;
}

Prevention

When it happens

Trigger: Calling deleteInternalSetting with a non-site-admin token, a site admin lacking manage_internal_settings, or passing the id of a secret setting (Setting.secret == true).

Common situations: Developers using regular account-admin tokens instead of site-admin credentials, or attempting to delete protected internal settings that Canvas intentionally hides from deletion.

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

Appendix: source

Thrown at app/graphql/mutations/delete_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::DeleteInternalSetting < Mutations::BaseMutation
  graphql_name "DeleteInternalSetting"

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

  field :internal_setting_id, ID, 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

    context[:deleted_models] = { internal_setting: }
    Setting.remove(internal_setting.name)

    { internal_setting_id: CanvasSchema.id_from_object(internal_setting, Types::InternalSettingType, nil) }
  rescue ActiveRecord::RecordNotFound
    raise GraphQL::ExecutionError, "not found"
  end

  def self.internal_setting_id_log_entry(_topic, context)
    context[:deleted_models][:internal_setting]
  end
end

View on GitHub (pinned to 1c9f0bb801)