teamcapybara/capybara · error · Capybara::ExpectationNotMet
result.failure_message
Error message
result.failure_message
What it means
Node::Finders#all raises Capybara::ExpectationNotMet (message built by Result#failure_message: 'expected to find <description> ... but there were no matches' or 'found N matches: ...') when the number of resolved elements does not satisfy the count options after waiting. `all` injects minimum: 1 unless you pass :count, :minimum or :between, so even finding zero plain elements can raise. It retries inside synchronize(query.wait) until the deadline before giving up.
Source
Thrown at lib/capybara/node/finders.rb:267
# When `true` allows elements to be reloaded if they become stale. This is an advanced behavior and should only be used
# if you fully understand the potential ramifications. The results can be confusing on dynamic pages. Defaults to `false`
# @overload all([kind = Capybara.default_selector], locator = nil, **options)
# @overload all([kind = Capybara.default_selector], locator = nil, **options, &filter_block)
# @yieldparam element [Capybara::Node::Element] The element being considered for inclusion in the results
# @yieldreturn [Boolean] Should the element be considered in the results?
# @return [Capybara::Result] A collection of found elements
# @raise [Capybara::ExpectationNotMet] The number of elements found doesn't match the specified conditions
def all(*args, allow_reload: false, **options, &optional_filter_block)
minimum_specified = options_include_minimum?(options)
options = { minimum: 1 }.merge(options) unless minimum_specified
options[:session_options] = session_options
query = Capybara::Queries::SelectorQuery.new(*args, **options, &optional_filter_block)
result = nil
begin
synchronize(query.wait) do
result = query.resolve_for(self)
result.allow_reload! if allow_reload
raise Capybara::ExpectationNotMet, result.failure_message unless result.matches_count?
result
end
rescue Capybara::ExpectationNotMet
raise if minimum_specified || (result.compare_count == 1)
Result.new([], nil)
end
end
alias_method :find_all, :all
##
#
# Find the first element on the page matching the given selector
# and options. By default {#first} will wait up to {Capybara.configure default_max_wait_time}
# seconds for matching elements to appear and then raise an error if no matching
# element is found, or `nil` if the provided count options allow for empty results.
#View on GitHub (pinned to 15b5fdb76e)
Solutions
- Verify the actual count first (page.all('li').size) and align the count option with reality
- Raise the wait: page.all('li', count: 3, wait: 5) or Capybara.default_max_wait_time = 5
- Relax the constraint to minimum:/between: when exact count is brittle (e.g. between: 2..4)
- If items are filtered out by :text/:visible, remove or correct the filter so intended items count
Example fix
# before
page.all('li.item', count: 3)
# after
page.all('li.item', count: 3, wait: 5)
# or tolerate async loading
page.all('li.item', minimum: 3, wait: 5) Defensive patterns
Strategy: retry
Validate before calling
expected = 3
found = page.all('li.item', wait: 5).size
page.all('li.item', count: expected) if found == expected Try / catch
begin
page.all('li.item', count: 3, wait: 5)
rescue Capybara::ExpectationNotMet => e
puts "actual: #{page.all('li.item').size} — #{e.message}"
raise
end Prevention
- Set default_max_wait_time to your app's realistic worst-case render time
- Prefer minimum:/between: over exact count: for lists that load progressively
- Assert a page-level marker first so the count query starts after content exists
When it happens
Trigger: page.all('li', count: 3) when the list has 2 or 4 items; page.all('.item', minimum: 5) on a partially rendered list; page.all('td') inside a table that has not rendered yet within default_max_wait_time. Note the rescue in the source: when only the implicit minimum: 1 applies and too many elements were found (Result#compare_count == 1), `all` silently returns an empty Result instead of raising.
Common situations: Async/paged content still loading when the count is taken; wrong expectation of item count after filtering; slow CI making the built-in wait too short; mixed-content lists where some items match filters (:text, :visible) and others do not — the failure message lists 'Also found ... which matched the selector but not all filters'.
Related errors
- result.failure_message
- Unable to find #{query.applied_description}
- res.join(' or ')
- result.negative_failure_message
- query.negative_failure_message
AI-assisted analysis of teamcapybara/capybara@15b5fdb76e (2026-08-21).
Data as JSON: /api/errors/d73d54cc80a6b440.
Report an issue: GitHub.