{"record":{"id":"9521c1878287ca0b","repo":"instructure/canvas-lms","slug":"insufficient-permission-create-internal-setting","errorCode":null,"errorMessage":"insufficient permission","messagePattern":"insufficient permission","errorType":"exception","errorClass":"GraphQL::ExecutionError","httpStatus":null,"severity":"error","filePath":"app/graphql/mutations/create_internal_setting.rb","lineNumber":29,"sourceCode":"#\n# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY\n# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR\n# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more\n# details.\n#\n# You should have received a copy of the GNU Affero General Public License along\n# with this program. If not, see <http://www.gnu.org/licenses/>.\n#\nclass Mutations::CreateInternalSetting < Mutations::BaseMutation\n  graphql_name \"CreateInternalSetting\"\n\n  argument :name, String, required: true\n  argument :value, String, required: true\n\n  field :internal_setting, Types::InternalSettingType, null: true\n  def resolve(input:)\n    unless Account.site_admin.grants_right?(current_user, :manage_internal_settings)\n      raise GraphQL::ExecutionError, \"insufficient permission\"\n    end\n\n    Setting.set(input[:name], input[:value])\n    internal_setting = Setting.find_by!(name: input[:name])\n\n    { internal_setting: }\n  rescue ActiveRecord::RecordInvalid => e\n    errors_for(e.record)\n  end\nend\n","sourceCodeStart":11,"sourceCodeEnd":40,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/mutations/create_internal_setting.rb#L11-L40","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nSetting.set(input[:name], input[:value]) // raises for non site-admins\n// after\ncontext[:site_admin_granted] = Account.site_admin.grants_right?(current_user, :manage_internal_settings)\nraise GraphQL::ExecutionError, 'insufficient permission' unless context[:site_admin_granted]\nSetting.set(input[:name], input[:value])","handlingStrategy":"validation","validationCode":"// GraphQL: check permissions on the viewer before mutating\nconst viewer = await gql(GET_VIEWER, { id })\nif (!viewer.siteAdmin || !viewer.permissions.manageInternalSettings) throw new Error('requires site admin with manage_internal_settings')","typeGuard":null,"tryCatchPattern":"try {\n  await gql(CREATE_INTERNAL_SETTING, { input })\n} catch (e) {\n  if (e.message === 'insufficient permission') showSiteAdminRequiredDialog()\n  else throw e\n}","preventionTips":["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."],"tags":["graphql","authorization","permissions","canvas-lms"],"backgroundTag":"permission-denied","analyzedSha":"1c9f0bb8013ed69c4f2efe11fd483025469b7e6c","analyzedAt":"2026-09-15T20:33:18.891Z","contentChangedAt":"2026-09-15T20:33:18.891Z","schemaVersion":2},"datasetVersion":"2026-09-23T02:17:17.105Z"}