microsoft/playwright · error · InvalidSelectorError
Error while parsing selector `${selector}` - selector cannot
Error message
Error while parsing selector `${selector}` - selector cannot be empty What it means
Thrown by parseAttributeSelector at the end of parsing when the selector has neither a name (engine prefix) nor any attributes. It signals the input reduced to nothing meaningful, e.g. an empty string or whitespace-only input fed to the attribute selector parser.
Source
Thrown at packages/isomorphic/selectorParser.ts:465
if (operator !== '=' && typeof value !== 'string')
throw new InvalidSelectorError(`Error while parsing selector \`${selector}\` - cannot use ${operator} in attribute with non-string matching value - ${value}`);
return { name: jsonPath.join('.'), jsonPath, op: operator, value, caseSensitive };
}
const result: AttributeSelector = {
name: '',
attributes: [],
};
result.name = readIdentifier();
skipSpaces();
while (next() === '[') {
result.attributes.push(readAttribute());
skipSpaces();
}
if (!EOL)
syntaxError(undefined);
if (!result.name && !result.attributes.length)
throw new InvalidSelectorError(`Error while parsing selector \`${selector}\` - selector cannot be empty`);
return result;
}
View on GitHub (pinned to c8fc3bf8d3)
Solutions
- Guard the caller to reject empty/whitespace selector strings before parsing.
- Provide a non-empty default or fail fast with a clearer upstream error.
- Trim and validate selector input at the boundary.
Example fix
// before
const name = process.env.LABEL ?? '';
page.locator(`text=${name}`); // name empty -> selector cannot be empty
// after
const name = (process.env.LABEL ?? '').trim();
if (!name) throw new Error('LABEL env var must be set');
page.locator(`text=${name}`); Defensive patterns
Strategy: validation
Validate before calling
function requireNonEmptySelector(sel: string) {
if (typeof sel !== 'string' || sel.trim().length === 0)
throw new Error('Selector must be a non-empty string');
}
requireNonEmptySelector(selector); Type guard
function isNonEmptySelector(sel: unknown): sel is string {
return typeof sel === 'string' && sel.trim().length > 0;
} Try / catch
try {
await page.locator(sel).click();
} catch (e) {
if (/selector cannot be empty/.test(e.message)) {
throw new Error('Refusing empty selector; check the source of the value');
}
throw e;
} Prevention
- Trim and validate selector inputs at API boundaries.
- Reject empty config values with a clearer upstream error.
- Default placeholders to a safe sentinel, never an empty string.
When it happens
Trigger: Calling `parseAttributeSelector('', false)`, `parseAttributeSelector(' ', false)`, or `parseAttributeSelector('[ ]', false)` where readIdentifier yields '' and no attributes are collected. Typically reached via the text/attribute engine with an empty inner expression.
Common situations: Dynamic selector assembly that produces an empty fragment; whitespace-only input from a config value; refactoring that left a placeholder variable empty.
Related errors
- Unsupported token "${unsupportedToken.toSource()}" while par
- Unexpected end of selector while parsing selector `${selecto
- Error while parsing css selector "${selector}". Did you mean
- Malformed selector: ${part.name}=${part.body}
- Error while parsing selector `${selector}`: ${e.message}
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/6e6693d21d90e39b.
Report an issue: GitHub.