symfony/css-selector · error · ExpressionErrorException
"*:last-of-type" is not implemented.
Error message
"*:last-of-type" is not implemented.
What it means
ExpressionErrorException thrown by PseudoClassExtension::translateLastOfType when the XPath element is '*'. Like :first-of-type, 'last element of its type' cannot be expressed against a universal selector, so '*:last-of-type' is rejected outright.
Solutions
- Replace '*' with a concrete element type: 'tr:last-of-type'.
- Use ':last-child' when any element type is acceptable.
- Catch ExpressionErrorException and handle the selector at the application level.
- Pre-process selectors to detect '*:last-of-type' before calling cssToXPath.
Example fix
// before '*:last-of-type' // after 'tr:last-of-type' // or '*:last-child'
Defensive patterns
Strategy: try-catch
Validate before calling
if (preg_match('/^\*:last-of-type$/', trim($selector))) {
throw new \InvalidArgumentException('Provide a concrete element type with :last-of-type.');
} Type guard
function universalLastOfType(string $css): bool {
return (bool) preg_match('/(^|[\s,+>~])\*:last-of-type/', $css);
} Try / catch
try {
$xpath = $translator->cssToXPath($css);
} catch (ExpressionErrorException $e) {
if (str_contains($e->getMessage(), 'last-of-type')) {
$xpath = $translator->cssToXPath(str_replace('*:last-of-type', '*:last-child', $css));
}
} Prevention
- Prefer :last-child over *:last-of-type.
- Attach :last-of-type only to concrete element selectors.
- Add selector lint rules banning '*:last-of-type'.
- Cover translator edge cases with unit tests.
When it happens
Trigger: Translating '*:last-of-type' or selectors normalized so the element is '*' with :last-of-type attached, via Translator::cssToXPath.
Common situations: Same confusion as with :first-of-type/:nth-last-of-type — using of-type pseudo-classes without a type selector; auto-generated or minified selectors losing the element name.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- "*:nth-of-type()" is not implemented.
- "*:first-of-type" is not implemented.
- Pseudo-class " " not supported.
- Pseudo-elements are not supported.
- Node " " not supported.
AI-assisted analysis of symfony/css-selector@08e2905152 (2026-09-14).
Data as JSON: /api/errors/13f257d0d8d1d454.
Report an issue: GitHub.
Appendix: source
Thrown at XPath/Extension/PseudoClassExtension.php:90
*/
public function translateFirstOfType(XPathExpr $xpath): XPathExpr
{
if ('*' === $xpath->getElement()) {
throw new ExpressionErrorException('"*:first-of-type" is not implemented.');
}
return $xpath
->addStarPrefix()
->addCondition('position() = 1');
}
/**
* @throws ExpressionErrorException
*/
public function translateLastOfType(XPathExpr $xpath): XPathExpr
{
if ('*' === $xpath->getElement()) {
throw new ExpressionErrorException('"*:last-of-type" is not implemented.');
}
return $xpath
->addStarPrefix()
->addCondition('position() = last()');
}
public function translateOnlyChild(XPathExpr $xpath): XPathExpr
{
return $xpath
->addStarPrefix()
->addNameTest()
->addCondition('last() = 1');
}
public function translateOnlyOfType(XPathExpr $xpath): XPathExpr
{
$element = $xpath->getElement();View on GitHub (pinned to 08e2905152)