symfony/css-selector · error · ExpressionErrorException

"*:nth-of-type()" is not implemented.

Error message

"*:nth-of-type()" is not implemented.

What it means

ExpressionErrorException thrown by FunctionExtension::translateNthLastOfType when the XPath expression's element is '*' (universal selector), i.e. the selector is like *:nth-last-of-type(). Counting by element type relative to the end is impossible when no element type is known, so the library refuses rather than emit wrong XPath.

Solutions

  1. Replace '*' with the concrete element type, e.g. 'p:nth-last-of-type(2)'.
  2. Use :nth-last-child() instead, which works with the universal selector.
  3. Catch ExpressionErrorException and fall back to a DOM/query library that supports this case.
  4. Filter or rewrite selectors containing '*:nth-of-type'/'*:nth-last-of-type' before translation.

Example fix

// before
'*:nth-last-of-type(2)'
// after
'p:nth-last-of-type(2)' // or 'p:nth-last-child(2)'
Defensive patterns

Strategy: try-catch

Validate before calling

if (preg_match('/^\*:(nth-last-of-type|nth-of-type)/', $selector)) {
    throw new \InvalidArgumentException('Rewrite *:nth-...-of-type with a concrete element type.');
}

Type guard

function needsElementTypeForOfType(string $css): bool {
    return (bool) preg_match('/(^|[\s,+>~])\*:(nth-)?(last-)?of-type/', $css);
}

Try / catch

try {
    $xpath = $translator->cssToXPath($css);
} catch (ExpressionErrorException $e) {
    if (str_contains($e->getMessage(), 'not implemented')) {
        $css = str_replace('*:nth-last-of-type', 'div:nth-last-child', $css);
        $xpath = $translator->cssToXPath($css);
    }
}

Prevention

When it happens

Trigger: Translating '*:nth-last-of-type(2)' or a compound where the type was erased to universal, e.g. '*:nth-last-of-type(1n)', through Translator::cssToXPath.

Common situations: Writing :nth-last-of-type() without a preceding element/type selector; automated selector generation that drops the element name; confusion between :nth-last-child (works on *) and :nth-last-of-type (does not).

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


AI-assisted analysis of symfony/css-selector@08e2905152 (2026-09-14). Data as JSON: /api/errors/03a2f4611043dcbd. Report an issue: GitHub.

Appendix: source

Thrown at XPath/Extension/FunctionExtension.php:119

    }

    public function translateNthLastChild(XPathExpr $xpath, FunctionNode $function): XPathExpr
    {
        return $this->translateNthChild($xpath, $function, true);
    }

    public function translateNthOfType(XPathExpr $xpath, FunctionNode $function): XPathExpr
    {
        return $this->translateNthChild($xpath, $function, false, false);
    }

    /**
     * @throws ExpressionErrorException
     */
    public function translateNthLastOfType(XPathExpr $xpath, FunctionNode $function): XPathExpr
    {
        if ('*' === $xpath->getElement()) {
            throw new ExpressionErrorException('"*:nth-of-type()" is not implemented.');
        }

        return $this->translateNthChild($xpath, $function, true, false);
    }

    /**
     * @throws ExpressionErrorException
     */
    public function translateContains(XPathExpr $xpath, FunctionNode $function): XPathExpr
    {
        $arguments = $function->getArguments();
        foreach ($arguments as $token) {
            if (!($token->isString() || $token->isIdentifier())) {
                throw new ExpressionErrorException('Expected a single string or identifier for :contains(), got '.implode(', ', $arguments));
            }
        }

        return $xpath->addCondition(\sprintf(

View on GitHub (pinned to 08e2905152)