symfony/css-selector · error · ExpressionErrorException

Pseudo-class " " not supported.

Error message

Pseudo-class "%s" not supported.

What it means

Translator::addPseudoClass() resolves a simple pseudo-class name (e.g. 'hover', 'first-child', 'empty') in $this->pseudoClassTranslators and throws ExpressionErrorException when the name is not registered. Static-state libraries only translate pseudo-classes that make sense in an XPath context, so many browser-only pseudo-classes are intentionally absent.

Solutions

  1. Remove the unsupported pseudo-class from the selector or replace it with a structural equivalent (e.g. :first-child is supported, :hover is not).
  2. Register a custom pseudo-class translator via Translator::extension().
  3. Check supported names: hover is registered, but classes like :visited/:target are typically not — consult pseudoClassTranslators keys.

Example fix

// before
$translator->cssToXPath('a:hover'); // pseudo-class not supported, throws

// after
$translator->cssToXPath('a'); // drop interactive pseudo-class, filter matches in code
Defensive patterns

Strategy: try-catch

Validate before calling

$supported = ['empty','first-child','last-child','first-of-type','last-of-type','only-child','hover','root','link','checked','disabled','enabled'];
$pseudo = implode('|', $supported);
if (preg_match('/:(' . $pseudo . ')?/)', '') !== false) { /* pre-check pseudo names */ }
if (!preg_match('/^:(?:' . $pseudo . ')$/', ':' . $name)) {
    throw new \InvalidArgumentException("Unsupported pseudo-class: $name");
}

Type guard

function pseudoClassSupported(string $name): bool {
    static $supported = ['first-child','last-child','empty','hover','root','link','checked','disabled','enabled'];
    return in_array(ltrim($name, ':'), $supported, true);
}

Try / catch

use Symfony\Component\CssSelector\Exception\ExpressionErrorException;
try {
    $xpath = $translator->cssToXPath($css);
} catch (ExpressionErrorException $e) {
    $css = preg_replace('/:hover|:focus|:active/', '', $css); // drop interactive pseudo-classes
    $xpath = $translator->cssToXPath($css);
}

Prevention

When it happens

Trigger: Calling addPseudoClass() with a $pseudoClass string missing from pseudoClassTranslators — e.g. selector ':hover', ':focus', ':visited' passed to the translator, or a misspelled pseudo-class like ':first-of-typee'.

Common situations: Feeding interactive/browser-only CSS (:hover, :focus, :active) to the XPath converter in scraping or testing code; typos in pseudo-class names; custom pseudo-classes without a registered translator.

Related errors


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

Appendix: source

Thrown at XPath/Translator.php:205

    /**
     * @throws ExpressionErrorException
     */
    public function addFunction(XPathExpr $xpath, FunctionNode $function): XPathExpr
    {
        if (!isset($this->functionTranslators[$function->getName()])) {
            throw new ExpressionErrorException(\sprintf('Function "%s" not supported.', $function->getName()));
        }

        return $this->functionTranslators[$function->getName()]($xpath, $function);
    }

    /**
     * @throws ExpressionErrorException
     */
    public function addPseudoClass(XPathExpr $xpath, string $pseudoClass): XPathExpr
    {
        if (!isset($this->pseudoClassTranslators[$pseudoClass])) {
            throw new ExpressionErrorException(\sprintf('Pseudo-class "%s" not supported.', $pseudoClass));
        }

        return $this->pseudoClassTranslators[$pseudoClass]($xpath);
    }

    /**
     * @throws ExpressionErrorException
     */
    public function addAttributeMatching(XPathExpr $xpath, string $operator, string $attribute, ?string $value): XPathExpr
    {
        if (!isset($this->attributeMatchingTranslators[$operator])) {
            throw new ExpressionErrorException(\sprintf('Attribute matcher operator "%s" not supported.', $operator));
        }

        return $this->attributeMatchingTranslators[$operator]($xpath, $attribute, $value);
    }

    /**

View on GitHub (pinned to 08e2905152)