teamcapybara/capybara · error · ArgumentError
Invalid CSS Selector - Block end '#{final}' not found
Error message
Invalid CSS Selector - Block end '#{final}' not found What it means
Capybara::Selector::CSS is the small parser Capybara uses to split/extend CSS selectors (for example when appending class or attribute conditions to a CSS locator). While scanning a bracket/paren block it consumes characters until the expected closing delimiter; hitting end-of-input first means the selector is unbalanced, and it raises ArgumentError naming the missing 'block end' character (e.g. ']' for an attribute selector or ')' for a functional pseudo-class).
Source
Thrown at lib/capybara/selector/css.rb:83
def parse_paren(strio)
parse_block('(', ')', strio)
end
def parse_block(start, final, strio)
block = start
while (char = strio.getc)
case char
when final
return block + char
when '\\'
block += char + strio.getc
when '"', "'"
block += parse_string(char, strio)
else
block += char
end
end
raise ArgumentError, "Invalid CSS Selector - Block end '#{final}' not found"
end
def parse_string(quote, strio)
string = quote
while (char = strio.getc)
string += char
case char
when quote
return string
when '\\'
string += strio.getc
end
end
raise ArgumentError, 'Invalid CSS Selector - string end not found'
end
end
end
endView on GitHub (pinned to 15b5fdb76e)
Solutions
- Balance the selector - every '(' and '[' opened must be closed in order.
- When building selectors from data, pass values as option hashes (class:, id:, text:) so Capybara escapes them, instead of interpolating raw strings into CSS.
- If a selector comes from external data, validate/parse it first (e.g. Nokogiri::CSS.parse) to fail with a clearer message before Capybara's splitting stage.
- Check for smart quotes or stray escapes when the selector text was copied out of a browser console or email.
Example fix
# before find(:css, "div[data-id='42'") # after find(:css, "div[data-id='42']")
Defensive patterns
Strategy: validation
Validate before calling
require 'nokogiri'
def balanced_css?(selector)
Nokogiri::CSS.parse(selector)
true
rescue Nokogiri::CSS::SyntaxError
false
end
selector = "div[data-id='42'"
raise ArgumentError, "unbalanced CSS: #{selector}" unless balanced_css?(selector) Type guard
def balanced_delimiters?(sel)
stack = []
sel.each_char do |c|
stack.push(c) if %w[( [ {].include?(c)
return false if %w[) ] }].include?(c) && stack.pop != { ')' => '(', ']' => '[', '}' => '{' }[c]
end
stack.empty?
end Prevention
- Build selectors from option hashes (class:, id:, text:) instead of string concatenation so Capybara escapes values.
- Validate data-derived selectors with Nokogiri::CSS.parse before passing them to find(:css, ...).
When it happens
Trigger: find(:css, 'div[data-id=\'42\''); find(:css, 'a:not(.external'); find(:css, 'tr:nth-child(2'); dynamically concatenated selectors where an interpolation dropped the closing bracket; class/attribute option values containing unbalanced brackets that get embedded into the CSS.
Common situations: Selector strings built by string interpolation or slicing (truncation cuts the tail); copy-paste from HTML/ERB that loses a character; data-driven selectors from fixtures or CSV; regex captures fed into find(:css, ...).
Related errors
- Invalid CSS Selector - string end not found
- This driver doesn't support case insensitive attribute match
- The rack_test driver does not process CSS
- XPath expressions are not supported for the :#{attribute} fi
- XPath expressions are not supported for the :class filter wi
AI-assisted analysis of teamcapybara/capybara@15b5fdb76e (2026-08-21).
Data as JSON: /api/errors/2ac77e840584312b.
Report an issue: GitHub.