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

  1. 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.
  2. If access is genuinely needed, an owner must change the membership's role; there is no self-service escalation.
  3. 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

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.