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
- Authenticate as a site admin (Account.site_admin) with :manage_internal_settings permission
- Check the setting is not secret via Setting before attempting deletion
- Verify the user's role overrides at the site-admin account level
- 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
- Use site-admin credentials for internal setting operations
- Skip settings flagged secret in the settings list UI
- Document required site-admin rights for the integration
- Verify role overrides before deploying automation
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
- insufficient permission
- feature flag is disabled
- insufficient permission
- insufficient permission
- insufficient permission
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)