{"record":{"id":"c06bce3b31781078","repo":"instructure/canvas-lms","slug":"group-not-found-move-outcome-links","errorCode":null,"errorMessage":"Group not found","messagePattern":"Group not found","errorType":"exception","errorClass":"GraphQL::ExecutionError","httpStatus":null,"severity":"error","filePath":"app/graphql/mutations/move_outcome_links.rb","lineNumber":65,"sourceCode":"    group.touch_parent_group if outcome_links.any?\n\n    context[:group] = group\n\n    {\n      errors:,\n      moved_outcome_links: ContentTag.where(id: outcome_links.pluck(:id))\n    }\n  end\n\n  def self.moved_outcome_link_ids_log_entry(_ids, ctx)\n    ctx[:group]\n  end\n\n  private\n\n  def get_group!(input)\n    LearningOutcomeGroup.active.find_by(id: input[:group_id]).tap do |group|\n      raise GraphQL::ExecutionError, I18n.t(\"Group not found\") unless group\n\n      if group.context\n        raise GraphQL::ExecutionError, I18n.t(\"Insufficient permission\") unless\n          group.context.grants_right?(current_user, session, :manage_outcomes)\n      else\n        raise GraphQL::ExecutionError, I18n.t(\"Insufficient permission\") unless\n          Account.site_admin.grants_right?(current_user, session, :manage_global_outcomes)\n      end\n    end\n  end\n\n  def get_outcome_links(input, context)\n    ids = input[:outcome_link_ids].map(&:to_i).uniq\n    links = if context\n              ContentTag.active.learning_outcome_links.where(\n                context:,\n                id: ids\n              )","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/mutations/move_outcome_links.rb#L47-L83","documentation":"MoveOutcomeLinks#get_group! looks up LearningOutcomeGroup.active.find_by(id: input[:group_id]); if no active group matches it raises this ExecutionError. Deleted (soft-deleted/workflow_state != active) or nonexistent groups both produce it.","triggerScenarios":"Calling moveOutcomeLinks with a group_id that does not exist, refers to a deleted/inactive outcome group, or is on another shard.","commonSituations":"Stale group IDs in frontend state after a group was deleted; using inactive groups from old links; environment/shard mismatch in multi-tenant installs.","solutions":["Verify the group_id references an active LearningOutcomeGroup","Re-fetch the outcome group structure to get a current group ID","If the group is globally-scoped, confirm you are using the correct global group ID"],"exampleFix":"// before\nmoveOutcomeLinks(input: { groupId: 88, ... }) // group deleted\n// after\nmoveOutcomeLinks(input: { groupId: 102, ... }) // active group from fresh query","handlingStrategy":"validation","validationCode":"// verify the group is active before moving outcomes\nconst g = await client.query({ query: OUTCOME_GROUP, variables: { id: groupId } });\nif (!g.data?.learningOutcomeGroup || g.data.learningOutcomeGroup.workflowState !== 'active') {\n  throw new Error(`Outcome group ${groupId} is not active`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await client.mutate({ mutation: MOVE_OUTCOME_LINKS, variables: { input } });\n} catch (e) {\n  if (e.message.includes('Group not found')) {\n    // refetch the group tree and let the user re-pick a target group\n  }\n}","preventionTips":["Refresh group lists after any delete operations","Never persist group IDs across sessions/environments","Filter UI pickers to active groups only"],"tags":["graphql","not-found","outcomes"],"backgroundTag":"entity-not-found","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"}