{"record":{"id":"e26af003c4731f5a","repo":"activerecord-hackery/ransack","slug":"invalid-argument-args-class-supplied-to-sorts","errorCode":null,"errorMessage":"Invalid argument (#{args.class}) supplied to sorts=","messagePattern":"Invalid argument \\(#(.+?)\\) supplied to sorts=","errorType":"exception","errorClass":"InvalidSearchError","httpStatus":null,"severity":"error","filePath":"lib/ransack/search.rb","lineNumber":82,"sourceCode":"      case args\n      when Array\n        args.each do |sort|\n          if sort.kind_of? Hash\n            sort = Nodes::Sort.new(@context).build(sort)\n          else\n            sort = Nodes::Sort.extract(@context, sort)\n          end\n          self.sorts << sort if sort\n        end\n      when Hash\n        args.each do |index, attrs|\n          sort = Nodes::Sort.new(@context).build(attrs)\n          self.sorts << sort\n        end\n      when String\n        self.sorts = [args]\n      else\n        raise InvalidSearchError,\n        \"Invalid argument (#{args.class}) supplied to sorts=\"\n      end\n    end\n    alias :s= :sorts=\n\n    def sorts\n      @sorts\n    end\n    alias :s :sorts\n\n    def build_sort(opts = {})\n      new_sort(opts).tap do |sort|\n        self.sorts << sort\n      end\n    end\n\n    def new_sort(opts = {})\n      Nodes::Sort.new(@context).build(opts)","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/activerecord-hackery/ransack/blob/e82f6bab3956c5597e7debbefa218d9e94e58ceb/lib/ransack/search.rb#L64-L100","documentation":"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.","triggerScenarios":"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.","commonSituations":"Hand-edited or fuzzed query strings; programmatic sort assignment after refactoring from strings to symbols; API layers forwarding typed JSON into Ransack params unconverted.","solutions":["Pass sorts as strings: search.sorts = 'created_at desc' or ['name asc', 'created_at desc']","Convert untrusted values first: search.sorts = params[:q][:s].to_s.split(',') if it's a single field","Whitelist user-supplied sort columns before assignment: search.sorts = [\"#{permitted_column} #{dir}\"]"],"exampleFix":"# before\nsearch.sorts = :name\n# => Ransack::InvalidSearchError: Invalid argument (Symbol) supplied to sorts=\n\n# after\nsearch.sorts = 'name asc'\n# or\nsearch.sorts = ['name asc', 'created_at desc']","handlingStrategy":"validation","validationCode":"raw = params[:q][:s]\nsearch.sorts = case raw\nwhen String, Array, Hash then raw\nelse raw.to_s.presence  # coerce scalars to string, nil/blank is skipped by sorts\nend","typeGuard":"def sortable_arg?(arg)\n  arg.is_a?(String) || arg.is_a?(Array) || arg.is_a?(Hash)\nend","tryCatchPattern":"begin\n  search.sorts = sort_input\nrescue Ransack::InvalidSearchError => e\n  Rails.logger.info(\"Ignoring bad sort input #{sort_input.inspect}: #{e.message}\")\n  search.sorts = 'created_at desc'\nend","preventionTips":["Always submit q[s] as strings ('name asc'); convert symbols/JSON values with to_s before assignment","Whitelist sort column names from user input before building the sorts value","In APIs, document and validate the sort parameter shape (string or array of strings) at the boundary"],"tags":["ruby","rails","ransack","sorting","search-params","invalidsearcherror"],"backgroundTag":"invalid-params-structure","analyzedSha":"e82f6bab3956c5597e7debbefa218d9e94e58ceb","analyzedAt":"2026-08-21T19:30:23.639Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}