{"record":{"id":"f9810b97a2ebc096","repo":"instructure/canvas-lms","slug":"category-has-reached-the-maximum-number-of-tags","errorCode":null,"errorMessage":"category has reached the maximum number of tags","messagePattern":"category has reached the maximum number of tags","errorType":"exception","errorClass":"GraphQL::ExecutionError","httpStatus":null,"severity":"error","filePath":"app/graphql/mutations/create_institutional_tag.rb","lineNumber":44,"sourceCode":"             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\n      errors_for(tag)\n    rescue ActiveRecord::RecordNotFound\n      raise GraphQL::ExecutionError, \"not found\"\n    end","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/mutations/create_institutional_tag.rb#L26-L62","documentation":"The mutation enforces a per-category cap on active tags, read from DynamicSettings (consul) under institutional_tags/max_tags_per_category with a fallback of 50. If the count of active tags in the category is >= max_tags it raises this GraphQL::ExecutionError instead of creating another tag.","triggerScenarios":"createInstitutionalTag on a category whose active institutional_tags count has reached the configured maximum (from consul DynamicSettings 'institutional_tags' key, default 50).","commonSituations":"Bulk-importing tags into a pre-filled category; default 50 cap hit because the consul key is absent; migrations/import scripts creating tags in a loop; test environments where the cap was tuned low.","solutions":["Delete/deactivate unneeded tags in the category, then retry.","Raise the cap in consul: set institutional_tags/max_tags_per_category to a higher value (or the account's DynamicSettings override).","Move new tags to a different or new category.","If the cap seems wrong, verify DynamicSettings.find('institutional_tags')['max_tags_per_category'] resolves as expected (failsafe nil path falls back to 50)."],"exampleFix":"// before\nactive tags in category = 50 (cap 50) -> raise\n// after (consul)\n{ \"institutional_tags\": { \"max_tags_per_category\": \"200\" } } // then retry mutation","handlingStrategy":"validation","validationCode":"# pre-flight count check\nmax = DynamicSettings.find('institutional_tags')['max_tags_per_category', failsafe: nil]&.to_i || 50\nif category.institutional_tags.where(workflow_state: 'active').count >= max\n  raise \"category #{category.id} at cap (#{max})\"\nend","typeGuard":"function categoryHasTagCapacity(category, activeTagCount, max = 50) {\n  return activeTagCount < max;\n}","tryCatchPattern":"try {\n  await createInstitutionalTag({ variables })\n} catch (e) {\n  if (e.message.includes('maximum number of tags')) {\n    // deactivate old tags or create/use another category\n  }\n}","preventionTips":["Monitor active-tag counts per category in bulk jobs","Set an explicit max_tags_per_category value in consul instead of relying on the 50 default","Chunk imports and rotate across categories when near the cap","Alert before a category reaches the configured cap"],"tags":["graphql","rate-limit","configuration","canvas"],"backgroundTag":"value-out-of-range","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"}