{"record":{"id":"db6ea3b4f37dc3a3","repo":"instructure/canvas-lms","slug":"insufficient-permission-outcome-proficiency-base","errorCode":null,"errorMessage":"insufficient permission","messagePattern":"insufficient permission","errorType":"exception","errorClass":"GraphQL::ExecutionError","httpStatus":null,"severity":"error","filePath":"app/graphql/mutations/outcome_proficiency_base.rb","lineNumber":52,"sourceCode":"  end\n\n  protected\n\n  def attrs(input)\n    {\n      outcome_proficiency_ratings: input[:proficiency_ratings].map do |rating|\n        OutcomeProficiencyRating.new(**rating)\n      end\n    }\n  end\n\n  def context_taken?(record)\n    error = record.errors.first\n    error && error.attribute == :context_id && error.message == \"has already been taken\"\n  end\n\n  def check_permission(context)\n    raise GraphQL::ExecutionError, \"insufficient permission\" unless context.grants_right? current_user, :manage_proficiency_scales\n  end\n\n  def upsert(input, existing_record: nil, context: nil)\n    record = existing_record || OutcomeProficiency.find_by(context:)\n    if record\n      record.assign_attributes(workflow_state: \"active\")\n      record.replace_ratings(input[:proficiency_ratings])\n      record.assign_attributes(context:) unless context.nil?\n    else\n      record = OutcomeProficiency.new(context:, **attrs(input.to_h))\n    end\n    if record.save\n      { outcome_proficiency: record }\n    elsif existing_record.nil? && context_taken?(record)\n      upsert(input, context:)\n    else\n      errors_for(record)\n    end","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/mutations/outcome_proficiency_base.rb#L34-L70","documentation":"GraphQL mutation for outcome proficiency upserts raises this when the current user lacks the :manage_proficiency_scales right on the target context (account or course). check_permission is called before any upsert work, so the mutation always fails closed when the permission grant is absent.","triggerScenarios":"Calling OutcomeProficiencyCreate or OutcomeProficiencyUpdate mutation as a user (teacher, custom role, admin of a sub-account) whose effective rights on context do not include manage_proficiency_scales.","commonSituations":"Non-admin users or custom roles missing the 'Learning Outcomes - add/edit/mastery scales' permission; attempting to set mastery scales at an account level with only course-level rights; API tokens of a user rather than an site admin.","solutions":["Grant the user's role the manage_proficiency_scales permission on the target account or course (Account > Permissions).","Verify with context.grants_right?(user, :manage_proficiency_scales) in a Rails console before calling the mutation.","Use a token/session of a user with the required permission instead."],"exampleFix":"// before\nmutation { createOutcomeProficiency(input: {contextId: \"...\"}) { ... } }\n// after\n// first ensure caller has permission, e.g. as an account admin with mastery-scale rights,\n// or fix role overrides so manage_proficiency_scales is enabled for the user's role","handlingStrategy":"validation","validationCode":"// pre-check in console/server code before calling the mutation\nraise \"no permission\" unless context.grants_right?(current_user, :manage_proficiency_scales)","typeGuard":null,"tryCatchPattern":"try { await mutate(); } catch (e) { if (e.message === 'insufficient permission') showPermissionDialog(); }","preventionTips":["Check role permissions (Account > Permissions) before building UI that mutates proficiency scales.","Gate client UI on the current user's permissions provided via Canvas permissions metadata.","Test with the least-privileged role you intend to support."],"tags":["graphql","authorization","permissions","outcomes"],"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"}