activerecord-hackery/ransack · error · InvalidSearchError
No valid predicate for #{key}
Error message
No valid predicate for #{key} What it means
While parsing each q[...] condition key, Ransack strips a trailing predicate suffix (like _cont or _gteq) and looks it up with Predicate.named. If no known predicate remains — because the key has no suffix or an unrecognized one — Ransack raises InvalidSearchError, but only when unknown conditions are not being ignored (ransack! or ignore_unknown_conditions = false; plain Model.ransack ignores them by default).
Source
Thrown at lib/ransack/nodes/condition.rb:43
# TODO: Figure out what to do with multiple types of attributes,
# if anything. Tempted to go with "garbage in, garbage out" here.
if predicate.validate(condition.values, condition.default_type)
condition
else
nil
end
end
end
private
def extract_values_for_condition(key, context = nil)
str = key.dup
name = Predicate.detect_and_strip_from_string!(str)
predicate = Predicate.named(name)
unless predicate || Ransack.options[:ignore_unknown_conditions]
raise InvalidSearchError, "No valid predicate for #{key}"
end
if context.present?
str = context.ransackable_alias(str)
end
combinator =
if str.match(/_(or|and)_/)
$1
else
nil
end
if context.present? && context.attribute_method?(str)
attributes = [str]
else
attributes = str.split(/_and_|_or_/)
endView on GitHub (pinned to e82f6bab39)
Solutions
- Append a valid predicate suffix to the attribute key: name_cont, created_at_gteq, etc. (see Ransack::Translate or the wiki predicate list)
- If the predicate should exist, register it: Ransack.configure { |c| c.add_predicate(:my_pred, arel_predicate: 'eq') }
- If junk params are expected, use the non-strict Person.ransack(params[:q]) which ignores unknown conditions, or set Ransack.configure { |c| c.ignore_unknown_conditions = true }
- Rescue Ransack::InvalidSearchError in the controller and fall back to an unfiltered result for malformed user input
Example fix
# before Person.ransack!(name: 'Alice') # => Ransack::InvalidSearchError: No valid predicate for name # after Person.ransack!(name_cont: 'Alice')
Defensive patterns
Strategy: try-catch
Validate before calling
KNOWN_PREDICATES = %w[eq not_eq cont start end gt lt gteq lteq in not_in null not_null true false present blank matches does_not_match].freeze
def sanitized_ransack_params(raw)
raw.select do |key, _|
key == 's' || key == 'sorts' ||
key.to_s.split(/_(or|and)_/).all? { |part|
part.match?(/_(#{KNOWN_PREDICATES.join('|')})$/)
}
end
end
Person.ransack!(sanitized_ransack_params(params[:q])) Type guard
def valid_condition_key?(key)
Ransack::Predicate.named(
Ransack::Predicate.detect_and_strip_from_string!(key.dup)
).present?
end Try / catch
begin
@q = Person.ransack!(params[:q])
@people = @q.result
rescue Ransack::InvalidSearchError => e
flash.now[:alert] = 'Invalid search filters; showing all records.'
Rails.logger.info("Bad ransack params: #{e.message}")
@q = Person.ransack
@people = Person.all
end Prevention
- Standardize search inputs on Ransack's form helpers so every field name ends in a valid predicate
- Register custom predicates in an initializer so forms and parsing agree
- Reserve ransack! for trusted/internal callers; use ransack for end-user facing endpoints, or rescue InvalidSearchError as a 4xx
When it happens
Trigger: Person.ransack!('name' => 'x') — key lacks a predicate suffix; a typo'd predicate like name_conct or value_gte (missing q); a custom predicate used in the form but never registered via Ransack.configure { config.add_predicate }; URL params crafted or truncated by hand (q[c][0][a]=name with no _eq).
Common situations: Using strict ransack! in controllers to surface bad params; renaming/removing a custom predicate while view forms still submit the old suffix; hand-built search URLs missing suffixes; Ransack upgrades where a predicate name changed.
Related errors
- Invalid search term #{key}
- Invalid argument (#{args.class}) supplied to sorts=
- #{type} cannot be converted to an ARel join type
- #{value} cannot be converted to a Class
- Don't know how to klassify #{obj}
AI-assisted analysis of activerecord-hackery/ransack@e82f6bab39 (2026-08-21).
Data as JSON: /api/errors/dc0f3a2c0a803ddb.
Report an issue: GitHub.