symfony/css-selector · error · ExpressionErrorException
Expected a single string or identifier for :lang(), got
Error message
Expected a single string or identifier for :lang(), got
What it means
ExpressionErrorException thrown by FunctionExtension::translateLang (plain XPath extension) when any argument token of :lang() is neither a string nor an identifier. The translator builds a lang(...) XPath condition from a literal value only, so other token types are rejected before the condition is emitted.
Solutions
- Quote the language code as a string: ':lang("en")'.
- Use a plain identifier: ':lang(en)'.
- Pass exactly one language per :lang() and combine selectors for multiple languages: ':lang(en), :lang(fr)'.
- Catch ExpressionErrorException and validate :lang() arguments before translating.
Example fix
// before
'p:lang(12)'
// after
'p:lang("en")' Defensive patterns
Strategy: validation
Validate before calling
foreach ($args as $arg) {
if (!preg_match('/^("[^"]*"|\'[\w-]*\'|[A-Za-z][\w-]*)$/', $arg)) {
throw new \InvalidArgumentException(':lang() argument must be a quoted string or identifier.');
}
} Try / catch
try {
$xpath = $translator->cssToXPath($css);
} catch (ExpressionErrorException $e) {
if (str_contains($e->getMessage(), ':lang()')) {
// reject selector
}
} Prevention
- Quote language codes: :lang("en").
- Pass exactly one language per :lang(); combine selectors for multiple.
- Use standard BCP-47-ish tags (letters/hyphens) that tokenize as identifiers.
- Validate generated :lang() values before translation.
When it happens
Trigger: Translating selectors like 'p:lang(123)', ':lang(en, fr)' where one of the tokens is not string/identifier, or constructing a FunctionNode with non-literal tokens programmatically and running it through Translator::cssToXPath.
Common situations: Unquoted language codes containing characters that tokenize as numbers, generated selectors feeding raw values, confusion with the CSS4 multi-argument :lang() which this library does not support this way.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Expected a single string or identifier for :lang(), got
- Expected a single string or identifier for :contains(), got
- Got too deeply nested
- Invalid series: " ".
- "*:nth-of-type()" is not implemented.
AI-assisted analysis of symfony/css-selector@08e2905152 (2026-09-14).
Data as JSON: /api/errors/fdae120d84ed40bf.
Report an issue: GitHub.
Appendix: source
Thrown at XPath/Extension/FunctionExtension.php:151
throw new ExpressionErrorException('Expected a single string or identifier for :contains(), got '.implode(', ', $arguments));
}
}
return $xpath->addCondition(\sprintf(
'contains(string(.), %s)',
Translator::getXpathLiteral($arguments[0]->getValue())
));
}
/**
* @throws ExpressionErrorException
*/
public function translateLang(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 :lang(), got '.implode(', ', $arguments));
}
}
return $xpath->addCondition(\sprintf(
'lang(%s)',
Translator::getXpathLiteral($arguments[0]->getValue())
));
}
public function getName(): string
{
return 'function';
}
}
View on GitHub (pinned to 08e2905152)