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
- 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)
- Read the %p list in the message and delete/rename each listed key (e.g. :perpage -> :per_page)
- 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
- Never forward arbitrary params hashes into paginate; always slice to :page/:per_page/:total_entries
- Treat finder options inside paginate as a Rails-2 smell in review: conditions/order/joins belong in the scope chain
- During Rails 2 -> 3+ upgrades, grep for 'paginate(' and audit each options hash with the whitelist above
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
- :page parameter required
- invalid #{name}: #{value.inspect}
- :renderer not specified
- The #{collection_name} variable appears to be empty. Did you
- DEPRECATION WARNING: #{message} (called from #{offending_lin
AI-assisted analysis of mislav/will_paginate@50017c3eb0 (2026-08-21).
Data as JSON: /api/errors/8431af4acdc36f41.
Report an issue: GitHub.