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
- Perform the mutation as a user with site-admin membership on Account.site_admin (grant :manage_internal_settings).
- Verify the bearer token / session actually resolves to that site-admin user, not an masquerade or expired session.
- 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.
- 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
- Document that this mutation is site-admin-only in API clients.
- Hide internal-setting UI for non site-admin users.
- Verify token identity/masquerade state before privileged calls.
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)