padrino/padrino-framework · error · Padrino::Admin::AccessControlError
Role #{role} must be present and must be a symbol!
Error message
Role #{role} must be present and must be a symbol! What it means
Padrino::Admin::AccessControl::Base#roles_for maps project modules to roles and validates its arguments: at least one role must be supplied and every role must be a Symbol (:admin, not 'admin'). Note a latent bug in this source: the message interpolates an undefined variable `role` (the parameter is `roles`), so when this branch trips you may actually see a NameError about `role` instead of this text — the root cause is still an empty or non-Symbol role list.
Source
Thrown at padrino-admin/lib/padrino-admin/access_control.rb:47
app.send(:access_control=, Padrino::Admin::AccessControl::Base.new)
end
alias included registered
end
##
# This base access control class where roles are defined as are authorizations.
#
class Base
def initialize
@roles, @authorizations, @project_modules = [], [], []
end
##
# We map project modules for a given role or roles.
#
def roles_for(*roles, &block)
raise Padrino::Admin::AccessControlError, "Role #{role} must be present and must be a symbol!" if roles.any? { |r| !r.is_a?(Symbol) } || roles.empty?
raise Padrino::Admin::AccessControlError, "You can't merge :any with other roles" if roles.size > 1 && roles.any? { |r| r == :any }
@roles += roles
@authorizations << Authorization.new(*roles, &block)
end
##
# Return an array of roles.
#
def roles
@roles.uniq.reject { |r| r == :any }
end
##
# Return an array of project_modules.
#
def project_modules(account)
role = account.role.to_sym rescue :anyView on GitHub (pinned to 167044f3d5)
Solutions
- Pass at least one role and use Symbols: access_control.roles_for(:admin) do |role| ... end
- When roles come from config or the database, convert first: roles_for(*roles.map(&:to_sym))
- If you instead saw a NameError mentioning `role`, you hit the interpolation bug at access_control.rb:47 — fix the call as above, or patch the message to interpolate roles.inspect
Example fix
# before
access_control.roles_for('admin') do |role| ... end
# after
access_control.roles_for(:admin) do |role| ... end
# dynamic roles
access_control.roles_for(*config_roles.map(&:to_sym)) do |role| ... end Defensive patterns
Strategy: validation
Validate before calling
roles = Array(config_roles)
if roles.empty? || roles.any? { |r| !r.is_a?(Symbol) }
raise ArgumentError, "roles must be non-empty Symbols: #{roles.inspect}"
end
access_control.roles_for(*roles) { |role| ... } Type guard
def valid_roles?(*roles) = !roles.empty? && roles.all? { |r| r.is_a?(Symbol) } Try / catch
begin
access_control.roles_for(*roles, &block)
rescue Padrino::Admin::AccessControlError, NameError
warn "invalid access_control roles: #{roles.inspect}" # boot-time config bug — fix and re-run
raise
end Prevention
- Write roles as bare Symbols in app.rb; never quote them
- Convert external role data with .map(&:to_sym) before it reaches roles_for
- Treat AccessControlError (or a NameError on `role`) at boot as a config typo, not a runtime condition to rescue
When it happens
Trigger: Calling access_control.roles_for with no arguments (roles.empty?); passing strings like roles_for('admin'); passing role values read from ENV, YAML, params or a database that arrive as Strings; splatting a dynamic array whose entries are not Symbols.
Common situations: Editing the access_control block in admin/app.rb and quoting the role; building role lists from config files or a roles table; copying examples where the role came from user input (always a String).
Related errors
- You can't merge :any with other roles
- Adapter #{orm} is not yet supported!
- You must define an #{settings.admin_model} Model
- Popover requires tooltip.js
- <= At the moment, Padrino only supports #{supported_orm.join
AI-assisted analysis of padrino/padrino-framework@167044f3d5 (2026-08-23).
Data as JSON: /api/errors/82f845c7de799aaf.
Report an issue: GitHub.