CanCanCommunity/cancancan · error · CanCan::AuthorizationNotPerformed

This action failed the check_authorization because it does n

Error message

This action failed the check_authorization because it does not authorize_resource. Add skip_authorization_check to bypass this check.

What it means

check_authorization (lib/cancan/controller_additions.rb:271) installs an after_action callback that raises CanCan::AuthorizationNotPerformed unless the action actually performed an authorization decision (tracked via the @_authorized instance variable set by authorize!/authorize/load_and_authorize_resource). It is a safety net so no controller action ships without an explicit authorization choice; :if/:unless options skip the check for named controller methods.

Source

Thrown at lib/cancan/controller_additions.rb:271

      # [:+if+]
      #   Supply the name of a controller method to be called.
      #   The authorization check only takes place if this returns true.
      #
      #     check_authorization :if => :admin_controller?
      #
      # [:+unless+]
      #   Supply the name of a controller method to be called.
      #   The authorization check only takes place if this returns false.
      #
      #     check_authorization :unless => :devise_controller?
      #
      def check_authorization(options = {})
        block = proc do |controller|
          next if controller.instance_variable_defined?(:@_authorized)
          next if options[:if] && !controller.send(options[:if])
          next if options[:unless] && controller.send(options[:unless])

          raise AuthorizationNotPerformed,
                'This action failed the check_authorization because it does not authorize_resource. ' \
                'Add skip_authorization_check to bypass this check.'
        end

        send(:after_action, options.slice(:only, :except), &block)
      end

      # Call this in the class of a controller to skip the check_authorization behavior on the actions.
      #
      #   class HomeController < ApplicationController
      #     skip_authorization_check :only => :index
      #   end
      #
      # Any arguments are passed to the +before_action+ it triggers.
      def skip_authorization_check(*args)
        block = proc { |controller| controller.instance_variable_set(:@_authorized, true) }
        send(:before_action, *args, &block)
      end

View on GitHub (pinned to 8c1bf153a3)

Solutions

  1. Add authorize_resource or load_and_authorize_resource to the controller (preferred — the check exists to force this).
  2. For deliberately public actions, add skip_authorization_check :only => :index (or at the controller class level for fully public controllers).
  3. Exclude whole groups: check_authorization :unless => :devise_controller? or an :if predicate.
  4. For symbol subjects (pages with no model), call authorize! :read, :dashboard inside the action.

Example fix

# before
class ApplicationController < ActionController::Base
  check_authorization
end

class HomeController < ApplicationController
  def index; end  # raises AuthorizationNotPerformed
end

# after
class HomeController < ApplicationController
  skip_authorization_check only: :index
  def index; end
end
Defensive patterns

Strategy: validation

Validate before calling

# controller-level: make the decision explicit instead of forgetting it
class HomeController < ApplicationController
  skip_authorization_check only: :index # deliberate, visible choice
end

Try / catch

rescue_from CanCan::AuthorizationNotPerformed do |exception|
  Rails.logger.error("NO AUTHORIZATION: #{params[:controller]}##{params[:action]}")
  render file: 'public/500', status: :internal_server_error # fail loudly in dev
end

Prevention

When it happens

Trigger: ApplicationController declares check_authorization; any action in any controller that never calls authorize, authorize!, authorize_resource, or load_and_authorize_resource; controllers that only use can? in views (can? does not set @_authorized); Devise or other engine controllers not excluded via check_authorization unless: :devise_controller?.

Common situations: Adding public pages (home, about, health endpoints) and forgetting to skip; introducing a new namespaced controller while the ability rules live only in view guards; engines mounting controllers that bypass the app's authorize conventions.

Related errors


AI-assisted analysis of CanCanCommunity/cancancan@8c1bf153a3 (2026-08-21). Data as JSON: /api/errors/210b2e3c616c4d09. Report an issue: GitHub.