antiwork/gumroad · warning · Pundit::NotAuthorizedError
Your current role as #{team_membership.role.humanize} cannot
Error message
Your current role as #{team_membership.role.humanize} cannot perform this action. What it means
The role-specific sibling of error 293: build_error_message found a team membership for the signed-in user on the current seller, so the denial names their role — "Your current role as Admin/Marketing/Analyst cannot perform this action." Delivered by default_user_not_authorized as a 401 JSON body or a flash alert plus dashboard redirect. It means the user is authenticated and on the team, but their role's permissions do not cover this policy query.
Source
Thrown at app/controllers/concerns/pundit_authorization.rb:53
def settings_main_user_not_authorized
# This allows keeping the Nav link to settings_main_path, and redirect to the profile page for those roles
# that don't have access to it
# All roles have at least read-only access to the profile page
redirect_to profile_path
end
# It could happen for reasons like:
# - a UI element allows the user to access a resource that is not authorized
# - the user manually accessed a page for which is not authorized (i.e. /settings/password by non-owner)
# These are not usual use cases of the app, so logging it to be notified there are bugs that need fixing.
# Also, do not log and do not set a flash alert when the user is switching accounts, as this is a normal use case.
#
def default_user_not_authorized(exception)
Rails.logger.warn(debug_message(exception)) unless params["account_switched"]
message = build_error_message
if request.format.json? || request.format.js?
render json: { success: false, error: message }, status: :unauthorized
else
flash[:alert] = message unless params["account_switched"]
redirect_to dashboard_url
end
end
def build_error_message
# Some policies (like CommentContextPolicy#index?) do not require the user to be authenticated
return "You are not allowed to perform this action." if
!user_signed_in? ||
logged_in_user.role_owner_for?(current_seller)
team_membership = logged_in_user.find_user_membership_for_seller!(current_seller)
"Your current role as #{team_membership.role.humanize} cannot perform this action."
rescue ActiveRecord::RecordNotFound
# This should not happen, but if it does, we want to be notified so we can fix it
ErrorNotifier.notify("Team: Could not find membership for user #{logged_in_user.id} and seller #{current_seller.id}")View on GitHub (pinned to afeacbd394)
Solutions
- Compare the user's membership role for the seller against the policy's permitted roles — the warn log line includes policy class, user id, and seller id.
- If access is genuinely needed, an owner must change the membership's role; there is no self-service escalation.
- Developers: gate nav items and buttons on the pundit policy or membership role so the option is never offered to roles that would be denied.
Example fix
<%# before: shown to every team member %> <%= link_to "Team", settings_team_path %> <%# after: only roles whose policy allows it see the link %> <%= link_to "Team", settings_team_path if policy([:settings, :team]).show? %>
Defensive patterns
Strategy: validation
Validate before calling
<%# Scope settings navigation by the viewer's membership role %> <% if policy([:settings, :team]).show? %> <%= link_to "Team", settings_team_path %> <% end %>
Type guard
# Ruby: check the membership role before offering the action membership = logged_in_user.find_user_membership_for_seller(current_seller) can_manage_team = membership&.role.to_s.in?(%w[owner admin])
Try / catch
# Handled centrally by the concern (401 JSON or flash + dashboard redirect); # the message names the user's humanized role so support can explain the denial immediately
Prevention
- Derive visible navigation from pundit policies or membership role, not from mere login state.
- After changing a teammate's role, invalidate cached UI so stale links do not lead them into denials.
- Document each role's permitted areas so owners assign roles that match the teammate's tasks.
When it happens
Trigger: A non-owner team member (e.g. Marketing, Analyst) opens an owner-only page such as /settings/password; a role-scoped nav link points at a controller action their policy denies; an API call made with team-member credentials against an owner-only endpoint.
Common situations: New teammates exploring settings they cannot access; a role downgraded while cached UI still shows elevated links; frontend rendering actions based on login state rather than membership role.
Related errors
AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21).
Data as JSON: /api/errors/d007b1daefdce87e.
Report an issue: GitHub.