{"record":{"id":"cc1b0dc617cdba6c","repo":"instructure/canvas-lms","slug":"insufficient-permissions-create-learning-outcome-group","errorCode":null,"errorMessage":"Insufficient permissions","messagePattern":"Insufficient permissions","errorType":"exception","errorClass":"GraphQL::ExecutionError","httpStatus":null,"severity":"error","filePath":"app/graphql/mutations/create_learning_outcome_group.rb","lineNumber":54,"sourceCode":"    @child_outcome_group = @outcome_group.child_outcome_groups.build(attributes(input))\n    @child_outcome_group.saving_user = current_user\n    if @child_outcome_group.save\n      { learning_outcome_group: @child_outcome_group }\n    else\n      errors_for(@child_outcome_group)\n    end\n  end\n\n  private\n\n  def get_group(id)\n    LearningOutcomeGroup.active.find_by(id:).tap do |group|\n      raise GraphQL::ExecutionError, I18n.t(\"Group not found\") unless group\n    end\n  end\n\n  def check_user_permissions\n    raise GraphQL::ExecutionError, I18n.t(\"Insufficient permissions\") unless can_manage_outcomes\n  end\n\n  def can_manage_outcomes\n    if @outcome_group.context\n      @outcome_group.context.grants_right?(current_user, session, :manage_outcomes)\n    else\n      Account.site_admin.grants_right?(current_user, session, :manage_global_outcomes)\n    end\n  end\n\n  def attributes(input)\n    input.to_h.slice(:title, :description, :vendor_guid)\n  end\nend\n","sourceCodeStart":36,"sourceCodeEnd":69,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/mutations/create_learning_outcome_group.rb#L36-L69","documentation":"CreateLearningOutcomeGroup#check_user_permissions raises 'Insufficient permissions' unless can_manage_outcomes. can_manage_outcomes checks @outcome_group.context.grants_right?(current_user, session, :manage_outcomes); when the group has no context it falls back to site-admin manage rights. So the caller must hold :manage_outcomes in the group's context.","triggerScenarios":"Calling createLearningOutcomeGroup as a teacher in a course where the account restricts outcome management to admins; a sub-account admin operating on a group owned by the root account; unauthenticated requests (context grants nothing).","commonSituations":"Account-level 'manage outcomes' feature flag or role override turned off for the user's role; writing to a root-account group from a course-scoped tool; using a token that lost its admin role after rotation.","solutions":["Run the mutation as a user with :manage_outcomes on the target group's context (usually an account admin).","Check RoleOverride/permission settings for the user's role in that account and enable 'Manage Learning Outcomes' if appropriate.","Target a group whose context matches where the user has rights (course group for teachers).","Pre-flight the permission via GraphQL permissions fields on the context before calling the mutation."],"exampleFix":"// before\nawait gql(createLearningOutcomeGroupMutation, { input })\n// after\nconst perms = await gql(groupPermissionsQuery, { groupId })\nif (!perms.manageOutcomes) showNoPermissionToast()\nelse await gql(createLearningOutcomeGroupMutation, { input })","handlingStrategy":"validation","validationCode":"const perms = await gql(GROUP_MANAGE_PERMS, { groupId })\nif (!perms.manageOutcomes) throw new Error('requires manage_outcomes on the group context')","typeGuard":null,"tryCatchPattern":"try {\n  await gql(CREATE_OUTCOME_GROUP, { input })\n} catch (e) {\n  if (e.message === 'Insufficient permissions') showNoManageOutcomesNotice()\n  else throw e\n}","preventionTips":["Expose the manageOutcomes permission field in your UI gate.","For course groups confirm the account allows teacher-level outcome management.","Detect role changes (token reissue) and re-check permissions per session."],"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"}