{"record":{"id":"697f13e1aeedf94c","repo":"instructure/canvas-lms","slug":"not-found-create-institutional-tag","errorCode":null,"errorMessage":"not found","messagePattern":"not found","errorType":"exception","errorClass":"GraphQL::ExecutionError","httpStatus":null,"severity":"error","filePath":"app/graphql/mutations/create_institutional_tag.rb","lineNumber":40,"sourceCode":"\nmodule Mutations\n  class CreateInstitutionalTag < BaseMutation\n    argument :category_id,\n             ID,\n             required: true,\n             prepare: GraphQLHelpers.relay_or_legacy_id_prepare_func(\"InstitutionalTagCategory\")\n    argument :description, String, required: true\n    argument :name,        String, required: true\n\n    field :institutional_tag, Types::InstitutionalTagType, null: true\n\n    def resolve(input:)\n      root_account = context[:domain_root_account]\n      raise GraphQL::ExecutionError, \"feature flag is disabled\" unless root_account.feature_enabled?(:institutional_tags)\n      raise GraphQL::ExecutionError, \"not authorized\" unless root_account.grants_right?(current_user, session, :manage_institutional_tags_create)\n\n      category = root_account.institutional_tag_categories.where(workflow_state: \"active\").find_by(id: input[:category_id])\n      raise GraphQL::ExecutionError, \"not found\" unless category\n\n      max_tags = DynamicSettings.find(\"institutional_tags\")[\"max_tags_per_category\", failsafe: nil]&.to_i || 50\n      if category.institutional_tags.where(workflow_state: \"active\").count >= max_tags\n        raise GraphQL::ExecutionError, \"category has reached the maximum number of tags\"\n      end\n\n      tag = category.institutional_tags.new(\n        name: input[:name],\n        description: input[:description],\n        root_account:\n      )\n\n      if tag.save\n        { institutional_tag: tag }\n      else\n        errors_for(tag)\n      end\n    rescue ActiveRecord::RecordInvalid","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/mutations/create_institutional_tag.rb#L22-L58","documentation":"CreateInstitutionalTag looks up the tag category scoped to the root account and active workflow_state via find_by(id: input[:category_id]). If nothing matches, it raises this GraphQL::ExecutionError. This differs from the trailing RecordNotFound rescue: this is the pre-validation lookup failing silently (find_by returns nil).","triggerScenarios":"category_id does not exist; the category belongs to a different root account; the category has workflow_state other than 'active' (deleted/inactive); the relay/legacy ID preparation produced an unexpected id value.","commonSituations":"Passing an ID from another account or shard; querying a soft-deleted category; a client caching an old category ID after the category was deactivated; confusing legacy numeric IDs with relay global IDs (e.g. 'InstitutionalTagCategory-5' vs 5) if the prepare helper mismatches.","solutions":["Verify the category_id exists: root_account.institutional_tag_categories.find_by(id: ...) in console.","Confirm the category's workflow_state is 'active' (not deleted/inactive).","Check the ID is from the same root account; cross-account IDs will not be found.","If using a GraphQL global ID, confirm the relay_or_legacy_id_prepare_func decodes it to the expected legacy id.","Recreate/activate the category if it was deleted, then retry."],"exampleFix":"// before\n{ createInstitutionalTag(input: {categoryId: \"99\", name: \"Tier\", description: \"...\"}) } // category 99 inactive/absent\n// after\nconst category = await fetchActiveCategory();\ncreateInstitutionalTag({ variables: { categoryId: category.id, name: 'Tier', description: '...' } })","handlingStrategy":"validation","validationCode":"# resolve the ID client-side first\nconst category = await gql(`query($id: ID!){ institutionalTagCategory(id:$id){ id workflowState } }`, { id: categoryId });\nif (!category || category.workflowState !== 'active') throw new Error('category not found or inactive');","typeGuard":"function isActiveCategory(c) {\n  return c != null && c.workflowState === 'active';\n}","tryCatchPattern":"try {\n  await createInstitutionalTag({ variables: { categoryId } })\n} catch (e) {\n  if (e.message === 'not found') { /* refresh category list, ask user to pick again */ }\n}","preventionTips":["Always fetch category IDs from the same root account's query","Filter categories by workflowState active before offering them in the UI","Refresh cached category lists after deactivate/delete operations","Ensure global vs legacy ID formats match the mutation's prepare helper"],"tags":["graphql","not-found","ruby","activerecord"],"backgroundTag":"record-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"}