symfony/css-selector · error · SyntaxErrorException

identifier

Error message

identifier

What it means

TokenStream::getNextIdentifier() consumes the next token and requires it to be an identifier token (e.g. a tag or attribute name like 'div' or 'foo'). If the next token is anything else (a delimiter, string, hash, whitespace at the wrong place, etc.) it throws a Symfony CssSelector SyntaxErrorException created by SyntaxErrorException::unexpectedToken('identifier', $next), reporting the expected type and the offending token.

Solutions

  1. Fix the CSS selector so a valid identifier appears at that position (identifiers must match [-\w]+ / CSS ident syntax, e.g. 'p.name' not 'p.[').
  2. Validate or sanitize dynamically built selector strings before passing them to CssSelector (check that interpolated parts are non-empty and identifier-safe).
  3. Inspect the full exception message: it names the expected token type and the offending token, which pinpoints the exact character in the selector that is wrong.
  4. If you drive TokenStream directly, check $stream->getPeek()->isIdentifier() before calling getNextIdentifier(), or catch SyntaxErrorException to handle bad input gracefully.
  5. Wrap user-supplied selectors in try/catch (SyntaxErrorException extends ParseException) and surface a friendly validation message instead of crashing.

Example fix

// before: malformed selector, '.' followed by '['
$crawler->filter('div.[data-x]')->each(...);

// after: valid identifier after the combinator/attribute syntax
$crawler->filter('div[data-x]')->each(...);
Defensive patterns

Strategy: validation

Validate before calling

// Check the next token before consuming it
use Symfony\Component\CssSelector\Parser\Token;

function nextTokenIsIdentifier(Symfony\Component\CssSelector\Parser\TokenStream $stream): bool
{
    return $stream->getPeek()->isIdentifier();
}

// For raw selector strings: ensure each part is a valid identifier
function isValidCssIdentifier(string $s): bool
{
    return preg_match('/^-?[A-Za-z_][A-Za-z0-9_-]*$|^-[A-Za-z_][A-Za-z0-9_-]*$/', $s) === 1;
}

Type guard

function isIdentifierToken(Symfony\Component\CssSelector\Parser\Token $t): bool
{
    return $t->isIdentifier();
}

Try / catch

try {
    $value = $stream->getNextIdentifier();
} catch (Symfony\Component\CssSelector\Exception\SyntaxErrorException $e) {
    // $e->getMessage() names the offending token; reject the selector input
    throw new InvalidArgumentException('Invalid selector: ' . $e->getMessage(), 0, $e);
}

Prevention

When it happens

Trigger: Calling getNextIdentifier() (directly or through a grammar handler that expects a name) when the token stream's next token is not an identifier: e.g. parsing a selector where a name is missing or misplaced, such as ':attr(' followed by ')' or '=' instead of a name, or a custom parser built on the stream feeding it a hash/string/delimiter token.

Common situations: Passing a malformed CSS selector string to Symfony CssSelector (e.g. via Crawler::filter() or cssToXpath()) such as 'p[' or '::=div'; typos in hand-written selectors; dynamic selectors built from user input or variables that interpolate to empty/illegal names; version changes in tokenizer behavior altering how a character is classified.

Related errors


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

Appendix: source

Thrown at Parser/TokenStream.php:119

     *
     * @return Token[]
     */
    public function getUsed(): array
    {
        return $this->used;
    }

    /**
     * Returns next identifier token.
     *
     * @throws SyntaxErrorException If next token is not an identifier
     */
    public function getNextIdentifier(): string
    {
        $next = $this->getNext();

        if (!$next->isIdentifier()) {
            throw SyntaxErrorException::unexpectedToken('identifier', $next);
        }

        return $next->getValue();
    }

    /**
     * Returns next identifier or null if star delimiter token is found.
     *
     * @throws SyntaxErrorException If next token is not an identifier or a star delimiter
     */
    public function getNextIdentifierOrStar(): ?string
    {
        $next = $this->getNext();

        if ($next->isIdentifier()) {
            return $next->getValue();
        }

View on GitHub (pinned to 08e2905152)