{"record":{"id":"df42233a2378e733","repo":"CanCanCommunity/cancancan","slug":"you-can-t-specify-target-target-as-alias-beca","errorCode":null,"errorMessage":"You can't specify target (#{target}) as alias because it is real action name","messagePattern":"You can't specify target \\(#(.+?)\\) as alias because it is real action name","errorType":"exception","errorClass":"CanCan::Error","httpStatus":null,"severity":"error","filePath":"lib/cancan/ability.rb","lineNumber":167,"sourceCode":"    #\n    #   can :read, :all\n    #   cannot :read, Comment\n    #\n    # A block can be passed just like \"can\", however if the logic is complex it is recommended\n    # to use the \"can\" method.\n    #\n    #   cannot :read, Product do |product|\n    #     product.invisible?\n    #   end\n    #\n    def cannot(action = nil, subject = nil, *attributes_and_conditions, &block)\n      add_rule(Rule.new(false, action, subject, *attributes_and_conditions, &block))\n    end\n\n    # User shouldn't specify targets with names of real actions or it will cause Seg fault\n    def validate_target(target)\n      error_message = \"You can't specify target (#{target}) as alias because it is real action name\"\n      raise Error, error_message if aliased_actions.values.flatten.include? target\n    end\n\n    def model_adapter(model_class, action)\n      adapter_class = ModelAdapters::AbstractAdapter.adapter_class(model_class)\n      adapter_class.new(model_class, relevant_rules_for_query(action, model_class))\n    end\n\n    # See ControllerAdditions#authorize! for documentation.\n    def authorize!(action, subject, *args)\n      message = args.last.is_a?(Hash) && args.last.key?(:message) ? args.pop[:message] : nil\n      if cannot?(action, subject, *args)\n        message ||= unauthorized_message(action, subject)\n        raise AccessDenied.new(message, action, subject, args)\n      end\n      subject\n    end\n\n    def attributes_for(action, subject)","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/CanCanCommunity/cancancan/blob/8c1bf153a3da7b2261d6fa4a5f84eb28e2feb828/lib/cancan/ability.rb#L149-L185","documentation":"Ability#validate_target (lib/cancan/ability.rb:167) runs on every alias_action call. A new alias target must not collide with any action name that already appears as a source action in aliased_actions (the flattened values), because an alias expands to its component actions at rule-match time and a target that is itself a real action would make matching ambiguous. Default aliases (read => [index, show], etc.) already occupy the common RESTful names.","triggerScenarios":"alias_action :read, to: :show raises because :show is a real (default-aliased) action name; aliasing to a name already used as a source in another alias, e.g. alias_action :create, :read, to: :crud followed by alias_action :crud, to: :manage is fine, but alias_action :crud, to: :read-style reuse of occupied names is not; merging abilities whose alias vocabularies overlap this way.","commonSituations":"Teams inventing CRUD meta-actions (:crud, :see, :modify) and accidentally reusing RESTful verb names; copy-pasting alias_action lines between apps with different alias sets; upgrading when default aliases changed.","solutions":["Pick a target name that is not an existing action or alias source (:see, :browse, :crud, :manage are safe vocabulary).","If you want an 'alias of an alias', alias the same underlying actions directly to the new target instead of chaining.","Inspect collisions first: puts ability.aliased_actions in a console to see every occupied name (keys and flattened values)."],"exampleFix":"# before\nalias_action :index, :show, to: :read   # default\nalias_action :read, to: :show           # CanCan::Error: target :show is a real action name\n\n# after\nalias_action :index, :show, to: :read   # default\nalias_action :read, to: :see            # :see is not an existing action name","handlingStrategy":"validation","validationCode":"target = :see\noccupied = ability.aliased_actions.values.flatten.map(&:to_s)\nraise ArgumentError, \"#{target} collides with a real action\" if occupied.include?(target.to_s)\nability.alias_action :index, :show, to: target","typeGuard":null,"tryCatchPattern":"begin\n  alias_action :read, to: :see\nrescue CanCan::Error => e\n  Rails.logger.error(\"alias collision: #{e.message}\")\nend","preventionTips":["Keep a fixed alias vocabulary (:see, :crud, :manage, :browse) documented in the Ability class.","Never chain alias_action targets; alias underlying actions directly.","Print ability.aliased_actions in a console session before adding new aliases.","Unit-test the Ability's alias table so accidental collisions fail in CI, not in production boots."],"tags":["alias-action","naming","rule-definition","cancancan","ruby"],"backgroundTag":"alias-name-collision","analyzedSha":"8c1bf153a3da7b2261d6fa4a5f84eb28e2feb828","analyzedAt":"2026-08-21T20:05:55.000Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}