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)
endView on GitHub (pinned to 8c1bf153a3)
Solutions
- Add authorize_resource or load_and_authorize_resource to the controller (preferred — the check exists to force this).
- For deliberately public actions, add skip_authorization_check :only => :index (or at the controller class level for fully public controllers).
- Exclude whole groups: check_authorization :unless => :devise_controller? or an :if predicate.
- 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
- Keep check_authorization in ApplicationController with unless: :devise_controller? from day one.
- Prefer authorize_resource over skip_authorization_check when in doubt.
- Add a CI spec enumerating routes and asserting each protected action sets @_authorized.
- Treat a new AuthorizationNotPerformed as a build failure, never silence it in production.
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
- You are not authorized to access this page.
- You are not authorized to access this page.
- The accessible_by call cannot be used with a block 'can' def
- Association '#{key}' not defined in model '#{model_class.nam
- You can't specify target (#{target}) as alias because it is
AI-assisted analysis of CanCanCommunity/cancancan@8c1bf153a3 (2026-08-21).
Data as JSON: /api/errors/210b2e3c616c4d09.
Report an issue: GitHub.