symfony/css-selector · error · ExpressionErrorException
Invalid series: " ".
Error message
Invalid series: "%s".
What it means
ExpressionErrorException thrown by FunctionExtension::translateNthChild when Parser::parseSeries cannot extract valid (a, b) coefficients from the arguments of :nth-child(), :nth-last-child(), :nth-of-type(), or :nth-last-of-type(). parseSeries throws SyntaxErrorException for malformed An+B expressions; this wraps it with the offending argument list.
Solutions
- Fix the selector's nth expression to a valid An+B form: integer, 'odd', 'even', 'an', 'an+b', '-an+b', 'n', '2n+1', etc.
- Catch Symfony\Component\CssSelector\Exception\ExpressionErrorException around the translation call.
- Validate the nth argument with a regex such as /^([+-]?\d*n)?\s*([+-]\s*\d+)?$/ before translating.
- Upgrade the library — some edge-case series parse failures were fixed in newer css-selector releases.
Example fix
// before 'li:nth-child(2 n + 1)' // after 'li:nth-child(2n+1)'
Defensive patterns
Strategy: validation
Validate before calling
function isValidAnB(?string $expr): bool {
return null !== $expr && (bool) preg_match('/^([+-]?\d*n)?\s*([+-]\s*\d+)?$|^odd$|^even$/i', trim($expr));
}
// validate each :nth-child() argument before cssToXPath Try / catch
try {
$xpath = $translator->cssToXPath($css);
} catch (\Symfony\Component\CssSelector\Exception\ExpressionErrorException $e) {
if (str_starts_with($e->getMessage(), 'Invalid series:')) {
// fix or reject the nth expression
}
} Prevention
- Only emit canonical An+B forms: 'odd', 'even', '2n+1', '-n+3'.
- Trim whitespace inside nth expressions.
- Validate programmatically generated nth values against the An+B regex.
- Keep css-selector current; parseSeries edge cases get fixed over time.
When it happens
Trigger: Translating a selector like li:nth-child(odd extra), li:nth-child(n+b+1), li:nth-child(1.5n), or an empty :nth-child() — any argument that is not a valid 'an+b' series — via Translator::cssToXPath.
Common situations: Typos in hand-written selectors, localized 'odd/even' spelled differently, user-supplied selectors with invalid formulas, passing values like 'even,' with stray commas.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- String not allowed as function argument.
- Got too deeply nested
- "*:nth-of-type()" is not implemented.
- Expected a single string or identifier for :contains(), got
- Expected a single string or identifier for :lang(), got
AI-assisted analysis of symfony/css-selector@08e2905152 (2026-09-14).
Data as JSON: /api/errors/efba73c3108c415f.
Report an issue: GitHub.
Appendix: source
Thrown at XPath/Extension/FunctionExtension.php:53
return [
'nth-child' => $this->translateNthChild(...),
'nth-last-child' => $this->translateNthLastChild(...),
'nth-of-type' => $this->translateNthOfType(...),
'nth-last-of-type' => $this->translateNthLastOfType(...),
'contains' => $this->translateContains(...),
'lang' => $this->translateLang(...),
];
}
/**
* @throws ExpressionErrorException
*/
public function translateNthChild(XPathExpr $xpath, FunctionNode $function, bool $last = false, bool $addNameTest = true): XPathExpr
{
try {
[$a, $b] = Parser::parseSeries($function->getArguments());
} catch (SyntaxErrorException $e) {
throw new ExpressionErrorException(\sprintf('Invalid series: "%s".', implode('", "', $function->getArguments())), 0, $e);
}
$xpath->addStarPrefix();
if ($addNameTest) {
$xpath->addNameTest();
}
if (0 === $a) {
return $xpath->addCondition('position() = '.($last ? 'last() - '.($b - 1) : $b));
}
if ($a < 0) {
if ($b < 1) {
return $xpath->addCondition('false()');
}
$sign = '<=';
} else {View on GitHub (pinned to 08e2905152)