varvet/pundit · error · KeyError

No permissions in example metadata, did you forget to wrap w

Error message

No permissions in example metadata, did you forget to wrap with `permissions :show?, ...`?

What it means

Pundit's RSpec `permit` matcher reads the permission list from the current example's metadata, which is only populated by the `permissions :show?, ... do ... end` block from Pundit::RSpec::DSL (rspec.rb:131 stashes `metadata[:permissions]`). Calling the matcher from a plain `it`/`describe` block leaves the key absent, so `metadata.fetch(:permissions)` raises KeyError with this hint.

Source

Thrown at lib/pundit/rspec.rb:104

          # :nocov:
        end

        if ::RSpec.respond_to?(:current_example)
          def current_example
            ::RSpec.current_example
          end
        else
          # :nocov:
          # Compatibility with RSpec < 3.0, released 2014-06-01.
          def current_example
            example
          end
          # :nocov:
        end

        def permissions
          current_example.metadata.fetch(:permissions) do
            raise KeyError, <<~ERROR.strip
              No permissions in example metadata, did you forget to wrap with `permissions :show?, ...`?
            ERROR
          end
        end
      end
      # rubocop:enable Metrics/BlockLength
    end

    # Mixed in to all policy example groups to provide a DSL.
    module DSL
      # @example
      #   describe PostPolicy do
      #     permissions :show?, :update? do
      #       it { is_expected.to permit(user, own_post) }
      #     end
      #   end
      #
      # @example focused example group

View on GitHub (pinned to 06318683c9)

Solutions

  1. Wrap the example in a permissions block: `permissions :show? do it { is_expected.to permit(user, post) } end`.
  2. List every predicate the matcher should exercise: `permissions :show?, :update? do ... end` — one failing permission is reported in the matcher's failure message.
  3. Keep the spec under spec/policies or tagged `type: :policy` so Pundit::RSpec::PolicyExampleGroup (and thus the DSL) is included in the first place.
  4. To focus a run, append the symbol: `permissions :show?, :focus do ... end` — the DSL strips it and sets focus metadata.

Example fix

# before
describe PostPolicy do
  it { is_expected.to permit(user, post) } # KeyError: no :permissions metadata
end

# after
describe PostPolicy do
  permissions :show?, :update? do
    it { is_expected.to permit(user, post) }
  end
end
Defensive patterns

Strategy: validation

Validate before calling

# Inside a policy spec, guard before invoking the matcher:
unless defined?(RSpec.current_example) && RSpec.current_example.metadata.key?(:permissions)
  raise ArgumentError, "wrap examples in `permissions :show?, ... do ... end` before using permit"
end

Prevention

When it happens

Trigger: Writing `describe PostPolicy do it { is_expected.to permit(user, post) } end` (no permissions wrapper); moving a `permit` expectation into a shared example or helper method that runs outside a permissions block; using `specify`/custom example groups without the DSL wrapper; keeping specs written against an older style where permissions were inferred rather than declared.

Common situations: Copy-pasting policy specs from blog posts or generators that predate the permissions DSL; refactoring policy specs into shared contexts and losing the wrapper; spec files under spec/policies (or with `type: :policy`) so the DSL is loaded, but examples structured as plain `it` blocks.

Related errors


AI-assisted analysis of varvet/pundit@06318683c9 (2026-08-21). Data as JSON: /api/errors/437ccccb9a0350a1. Report an issue: GitHub.