{"record":{"id":"2f2bf3be29e0dace","repo":"symfony/css-selector","slug":"identifier","errorCode":null,"errorMessage":"identifier","messagePattern":"identifier","errorType":"exception","errorClass":"SyntaxErrorException","httpStatus":null,"severity":"error","filePath":"Parser/TokenStream.php","lineNumber":119,"sourceCode":"     *\n     * @return Token[]\n     */\n    public function getUsed(): array\n    {\n        return $this->used;\n    }\n\n    /**\n     * Returns next identifier token.\n     *\n     * @throws SyntaxErrorException If next token is not an identifier\n     */\n    public function getNextIdentifier(): string\n    {\n        $next = $this->getNext();\n\n        if (!$next->isIdentifier()) {\n            throw SyntaxErrorException::unexpectedToken('identifier', $next);\n        }\n\n        return $next->getValue();\n    }\n\n    /**\n     * Returns next identifier or null if star delimiter token is found.\n     *\n     * @throws SyntaxErrorException If next token is not an identifier or a star delimiter\n     */\n    public function getNextIdentifierOrStar(): ?string\n    {\n        $next = $this->getNext();\n\n        if ($next->isIdentifier()) {\n            return $next->getValue();\n        }\n","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/symfony/css-selector/blob/08e2905152a39cf3fd1745d83f8c483e258887d9/Parser/TokenStream.php#L101-L137","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.[').","Validate or sanitize dynamically built selector strings before passing them to CssSelector (check that interpolated parts are non-empty and identifier-safe).","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.","If you drive TokenStream directly, check $stream->getPeek()->isIdentifier() before calling getNextIdentifier(), or catch SyntaxErrorException to handle bad input gracefully.","Wrap user-supplied selectors in try/catch (SyntaxErrorException extends ParseException) and surface a friendly validation message instead of crashing."],"exampleFix":"// before: malformed selector, '.' followed by '['\n$crawler->filter('div.[data-x]')->each(...);\n\n// after: valid identifier after the combinator/attribute syntax\n$crawler->filter('div[data-x]')->each(...);","handlingStrategy":"validation","validationCode":"// Check the next token before consuming it\nuse Symfony\\Component\\CssSelector\\Parser\\Token;\n\nfunction nextTokenIsIdentifier(Symfony\\Component\\CssSelector\\Parser\\TokenStream $stream): bool\n{\n    return $stream->getPeek()->isIdentifier();\n}\n\n// For raw selector strings: ensure each part is a valid identifier\nfunction isValidCssIdentifier(string $s): bool\n{\n    return preg_match('/^-?[A-Za-z_][A-Za-z0-9_-]*$|^-[A-Za-z_][A-Za-z0-9_-]*$/', $s) === 1;\n}","typeGuard":"function isIdentifierToken(Symfony\\Component\\CssSelector\\Parser\\Token $t): bool\n{\n    return $t->isIdentifier();\n}","tryCatchPattern":"try {\n    $value = $stream->getNextIdentifier();\n} catch (Symfony\\Component\\CssSelector\\Exception\\SyntaxErrorException $e) {\n    // $e->getMessage() names the offending token; reject the selector input\n    throw new InvalidArgumentException('Invalid selector: ' . $e->getMessage(), 0, $e);\n}","preventionTips":["Validate user- or config-supplied selector strings against ident syntax before parsing.","Never interpolate raw variables into selectors; escape or reject values that are not [-\\w]+.","Prefer higher-level APIs (cssToXpath, Crawler::filter) wrapped in try/catch for ParseException.","When driving TokenStream directly, use getPeek() to type-check tokens before consuming them.","Log the SyntaxErrorException message in tests for every selector template you generate."],"tags":["php","css-selector","syntax-error","tokenizer","symfony"],"backgroundTag":"invalid-identifier","analyzedSha":"08e2905152a39cf3fd1745d83f8c483e258887d9","analyzedAt":"2026-09-14T11:41:28.509Z","contentChangedAt":"2026-09-14T11:41:28.509Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}