activerecord-hackery/ransack · error · InvalidSearchError

Invalid argument (#{args.class}) supplied to sorts=

Error message

Invalid argument (#{args.class}) supplied to sorts=

What it means

Search#sorts= (aliased s=) accepts an Array of sort descriptors ('name asc', Sort nodes, or hashes), an indexed Hash of sort attribute hashes, or a single String like 'created_at desc'. Any other class — Integer, Symbol, or an arbitrary object — raises InvalidSearchError, because a sort cannot be extracted from it. It fires when q[s] arrives in an unexpected form or sorts are assigned programmatically.

Source

Thrown at lib/ransack/search.rb:82

      case args
      when Array
        args.each do |sort|
          if sort.kind_of? Hash
            sort = Nodes::Sort.new(@context).build(sort)
          else
            sort = Nodes::Sort.extract(@context, sort)
          end
          self.sorts << sort if sort
        end
      when Hash
        args.each do |index, attrs|
          sort = Nodes::Sort.new(@context).build(attrs)
          self.sorts << sort
        end
      when String
        self.sorts = [args]
      else
        raise InvalidSearchError,
        "Invalid argument (#{args.class}) supplied to sorts="
      end
    end
    alias :s= :sorts=

    def sorts
      @sorts
    end
    alias :s :sorts

    def build_sort(opts = {})
      new_sort(opts).tap do |sort|
        self.sorts << sort
      end
    end

    def new_sort(opts = {})
      Nodes::Sort.new(@context).build(opts)

View on GitHub (pinned to e82f6bab39)

Solutions

  1. Pass sorts as strings: search.sorts = 'created_at desc' or ['name asc', 'created_at desc']
  2. Convert untrusted values first: search.sorts = params[:q][:s].to_s.split(',') if it's a single field
  3. Whitelist user-supplied sort columns before assignment: search.sorts = ["#{permitted_column} #{dir}"]

Example fix

# before
search.sorts = :name
# => Ransack::InvalidSearchError: Invalid argument (Symbol) supplied to sorts=

# after
search.sorts = 'name asc'
# or
search.sorts = ['name asc', 'created_at desc']
Defensive patterns

Strategy: validation

Validate before calling

raw = params[:q][:s]
search.sorts = case raw
when String, Array, Hash then raw
else raw.to_s.presence  # coerce scalars to string, nil/blank is skipped by sorts
end

Type guard

def sortable_arg?(arg)
  arg.is_a?(String) || arg.is_a?(Array) || arg.is_a?(Hash)
end

Try / catch

begin
  search.sorts = sort_input
rescue Ransack::InvalidSearchError => e
  Rails.logger.info("Ignoring bad sort input #{sort_input.inspect}: #{e.message}")
  search.sorts = 'created_at desc'
end

Prevention

When it happens

Trigger: q[s]=123 submitted via a tampered URL to a ransack! search; search.sorts = :name (Symbol) in code; params like q[s][]= via a form control that submits a non-string; JSON payloads where the sort value is an integer or null object.

Common situations: Hand-edited or fuzzed query strings; programmatic sort assignment after refactoring from strings to symbols; API layers forwarding typed JSON into Ransack params unconverted.

Related errors


AI-assisted analysis of activerecord-hackery/ransack@e82f6bab39 (2026-08-21). Data as JSON: /api/errors/e26af003c4731f5a. Report an issue: GitHub.