mislav/will_paginate · error · ArgumentError

unsupported parameters: %p

Error message

unsupported parameters: %p

What it means

will_paginate's paginate() only consumes exactly three keys: :page, :per_page and :total_entries. After deleting those from a dup of the options hash, any remaining key makes it raise ArgumentError 'unsupported parameters: %p' formatted with the leftover keys. This is a hard rejection of old Active Record 2.x finder options (:conditions, :order, :include, :joins, :limit...) which AR3+ scopes replaced.

Source

Thrown at lib/will_paginate/active_record.rb:151

      private

      def copy_will_paginate_data(other)
        other.current_page = current_page unless other.current_page
        other.total_entries = nil if defined? @total_entries_queried
        other
      end
    end

    module Pagination
      def paginate(options)
        options  = options.dup
        pagenum  = options.fetch(:page) { raise ArgumentError, ":page parameter required" }
        options.delete(:page)
        per_page = options.delete(:per_page) || self.per_page
        total    = options.delete(:total_entries)

        if options.any?
          raise ArgumentError, "unsupported parameters: %p" % options.keys
        end

        rel = limit(per_page.to_i).page(pagenum)
        rel.total_entries = total.to_i          unless total.blank?
        rel
      end

      def page(num)
        rel = if ::ActiveRecord::Relation === self
          self
        elsif !defined?(::ActiveRecord::Scoping) or ::ActiveRecord::Scoping::ClassMethods.method_defined? :with_scope
          # Active Record 3
          scoped
        else
          # Active Record 4
          all
        end

View on GitHub (pinned to 50017c3eb0)

Solutions

  1. Move every non-pagination option into the scope chain before paginate: Model.where('salary > ?', 80000).order('created_at DESC').paginate(page: 1, per_page: 10)
  2. Read the %p list in the message and delete/rename each listed key (e.g. :perpage -> :per_page)
  3. If the hash is dynamic, whitelist it first: options.slice!(:page, :per_page, :total_entries)

Example fix

// before
@developers = Developer.paginate(page: params[:page], conditions: ['salary > ?', 80000], order: 'name')

// after
@developers = Developer.where('salary > ?', 80000).order('name').paginate(page: params[:page] || 1, per_page: 10)
Defensive patterns

Strategy: validation

Validate before calling

ALLOWED = %i[page per_page total_entries].freeze
extras = options.symbolize_keys.keys - ALLOWED
raise ArgumentError, "unsupported parameters: #{extras.inspect}" unless extras.empty?
Model.where(...).paginate(options)

Try / catch

begin
  relation.paginate(options)
rescue ArgumentError => e
  raise unless e.message.start_with?('unsupported parameters')
  # log the listed keys, then rebuild the call with scopes instead of finder options
  raise
end

Prevention

When it happens

Trigger: Model.paginate(page: 1, conditions: ['salary > ?', 80000]), .paginate(:page => 1, :order => 'created_at DESC'), or any paginate call whose hash still carries :include/:joins/:limit/:offset/:readonly or a typo'd key like :perpage. The message body will literally list the offending keys.

Common situations: Upgrading an app from Rails 2 / will_paginate 2.x, where finder options inside paginate were legal; copy-pasting pre-2010 pagination snippets; merging an options hash built for Model.find into paginate; fat-fingered keys that no longer fail silently.

Related errors


AI-assisted analysis of mislav/will_paginate@50017c3eb0 (2026-08-21). Data as JSON: /api/errors/8431af4acdc36f41. Report an issue: GitHub.