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
- Confirm the user has :manage_internal_settings on Account.site_admin (root Site Admin account), granting via site admin role if needed.
- 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.
- 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
- Restrict internal-setting mutations to site-admin service credentials
- Never expose secret settings through the GraphQL path; manage them in console/config
- Verify target Setting IDs before mutating
- Keep an inventory of which settings are marked secret
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
- insufficient permission
- insufficient permission
- insufficient permission
- insufficient permission
- insufficient permission
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)