microsoft/playwright · error · InvalidSelectorError
Error while parsing selector `${selector}` - cannot use ${op
Error message
Error while parsing selector `${selector}` - cannot use ${operator} in attribute with regular expression What it means
Thrown when an attribute selector uses a regex value (`/.../`) with an operator other than `=`. Regex matching only supports the plain equality operator; substring/prefix/suffix operators (*=, ^=, $=, |=, ~=) are incompatible with regex semantics and are rejected.
Source
Thrown at packages/isomorphic/selectorParser.ts:414
while (next() === '.') {
eat1();
jsonPath.push(readAttributeToken());
skipSpaces();
}
// check property is truthy: [enabled]
if (next() === ']') {
eat1();
return { name: jsonPath.join('.'), jsonPath, op: '<truthy>', value: null, caseSensitive: false };
}
const operator = readOperator();
let value = undefined;
let caseSensitive = true;
skipSpaces();
if (next() === '/') {
if (operator !== '=')
throw new InvalidSelectorError(`Error while parsing selector \`${selector}\` - cannot use ${operator} in attribute with regular expression`);
value = readRegularExpression();
} else if (next() === `'` || next() === `"`) {
value = readQuotedString(next()).slice(1, -1);
skipSpaces();
if (next() === 'i' || next() === 'I') {
caseSensitive = false;
eat1();
} else if (next() === 's' || next() === 'S') {
caseSensitive = true;
eat1();
}
} else {
value = '';
while (!EOL && (isCSSNameChar(next()) || next() === '+' || next() === '.'))
value += eat1();
if (value === 'true') {
value = true;
} else if (value === 'false') {View on GitHub (pinned to c8fc3bf8d3)
Solutions
- Replace the substring/prefix/suffix operator with `=` and fold the matching intent into the regex, e.g. `[class=/.*active.*/]`.
- If you need a prefix match, anchor the regex: `[href=/^https/]`.
- Drop the regex and use the plain operator with a literal string instead.
Example fix
// before
page.locator('[class*=/active/]');
// after
page.locator('[class=/.*active.*/]'); Defensive patterns
Strategy: validation
Validate before calling
function assertNoRegexWithSubstringOp(sel: string) {
if (/[\^$|~*]=\/.*\//.test(sel))
throw new Error('Regex attribute values may only use the = operator');
}
assertNoRegexWithSubstringOp(selector); Type guard
function regexUsesEqualsOnly(sel: string): boolean {
return !/(\*|\^|\$|\||~)=\/.*\//.test(sel);
} Try / catch
try {
await page.locator(sel).click();
} catch (e) {
if (/cannot use .* in attribute with regular expression/.test(e.message)) {
sel = sel.replace(/([*^$|~])=(\/.*\/)/, '=$2');
// retry once with corrected operator
}
throw e;
} Prevention
- Remember the rule: regex values require `=` only.
- Fold prefix/substring intent into the regex body (e.g. `^`/`.*`).
- Code-review selectors that combine slashes with operators.
When it happens
Trigger: Writing `page.locator('[class*=/active/]')`, `[href^=/https/]`, `[data-id$=/\d+/]`, or any `[attr OP /regex/]` where OP is not `=`.
Common situations: Mistakenly combining CSS substring-match operators with Playwright's regex extension; assuming `*=` works like `.*` with a regex; refactor that changed `=` to `*=` without removing the slashes.
Related errors
- Error while parsing selector `${selector}`: ${e.message}
- Unsupported token "${unsupportedToken.toSource()}" while par
- Error while parsing css selector "${selector}". Did you mean
- Malformed selector: ${part.name}=${part.body}
- Unexpected end of selector while parsing selector `${selecto
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/95f2fa69e4a4d4d1.
Report an issue: GitHub.