symfony/css-selector · error · SyntaxErrorException

string or identifier

Error message

string or identifier

What it means

This SyntaxErrorException is thrown when the value of an attribute selector comparison is neither an identifier nor a string (numbers are auto-cast to strings, but anything else fails). The parser reports 'Expected string or identifier, but X found.'

Solutions

  1. Quote the attribute value: '[data-x="value"]' instead of relying on a raw token in the value position.
  2. Ensure the interpolated value is a scalar and cast it: sprintf('[data-x="%s"]', (string) $value).
  3. Escape embedded quotes, or use single quotes for the CSS string when the value contains double quotes.
  4. Remove duplicated '=' from the operator before the value.

Example fix

// before
$xpath = $converter->toXPath(sprintf('div[data-id=%s]', $id)); // $id = ['a'] -> invalid token

// after
$xpath = $converter->toXPath(sprintf('div[data-id="%s"]', (string) $id));
Defensive patterns

Strategy: validation

Validate before calling

// always quote and escape the value when building attribute selectors
function attrSelector(string $attr, string $op, string $value): string {
    return sprintf('[%s%s"%s"]', $attr, $op, str_replace('"', '\\"', $value));
}

Type guard

function isQuotableScalar($v): bool {
    return is_scalar($v);
}

Prevention

When it happens

Trigger: Selectors like 'a[href="x"' where a stray token appears in the value position: 'div[data-x="a"b]', '[data-x=="v"]', an unquoted value containing invalid characters, or a value built by interpolating non-scalar data (array/null) into the selector string.

Common situations: Interpolating PHP variables that json_encode/array-cast oddly into the selector; double quotes inside single-quoted strings or vice versa breaking tokenization; operators accidentally duplicated so the second '=' lands in the value slot.

Related errors


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

Appendix: source

Thrown at Parser/Parser.php:465

                && $stream->getPeek()->isDelimiter(['='])
            ) {
                $operator = $next->getValue().'=';
                $stream->getNext();
            } else {
                throw SyntaxErrorException::unexpectedToken('operator', $next);
            }
        }

        $stream->skipWhitespace();
        $value = $stream->getNext();

        if ($value->isNumber()) {
            // if the value is a number, it's casted into a string
            $value = new Token(Token::TYPE_STRING, (string) $value->getValue(), $value->getPosition());
        }

        if (!($value->isIdentifier() || $value->isString())) {
            throw SyntaxErrorException::unexpectedToken('string or identifier', $value);
        }

        $stream->skipWhitespace();
        $next = $stream->getNext();

        if (!$next->isDelimiter([']'])) {
            throw SyntaxErrorException::unexpectedToken('"]"', $next);
        }

        return new Node\AttributeNode($selector, $namespace, $attribute, $operator, $value->getValue());
    }
}

View on GitHub (pinned to 08e2905152)