microsoft/playwright · error · InvalidSelectorError

Unexpected end of selector while parsing selector `${selecto

Error message

Unexpected end of selector while parsing selector `${selector}`

What it means

Thrown by parseAttributeSelector when the parser hits end-of-string in the middle of a sub-parse stage (quoted string, regex, identifier, operator, or attribute value). It is an InvalidSelectorError indicating the selector text is truncated or unterminated. The parser expected more characters but ran out of input before completing the current token.

Source

Thrown at packages/isomorphic/selectorParser.ts:286

  attributes: AttributeSelectorPart[],
};


export function parseAttributeSelector(selector: string, allowUnquotedStrings: boolean): AttributeSelector {
  let wp = 0;
  let EOL = selector.length === 0;

  const next = () => selector[wp] || '';
  const eat1 = () => {
    const result = next();
    ++wp;
    EOL = wp >= selector.length;
    return result;
  };

  const syntaxError = (stage: string|undefined) => {
    if (EOL)
      throw new InvalidSelectorError(`Unexpected end of selector while parsing selector \`${selector}\``);
    throw new InvalidSelectorError(`Error while parsing selector \`${selector}\` - unexpected symbol "${next()}" at position ${wp}` + (stage ? ' during ' + stage : ''));
  };

  function skipSpaces() {
    while (!EOL && /\s/.test(next()))
      eat1();
  }

  function isCSSNameChar(char: string) {
    // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram
    return (char >= '\u0080')  // non-ascii
        || (char >= '\u0030' && char <= '\u0039')  // digit
        || (char >= '\u0041' && char <= '\u005a')  // uppercase letter
        || (char >= '\u0061' && char <= '\u007a')  // lowercase letter
        || (char >= '\u0030' && char <= '\u0039')  // digit
        || char === '\u005f'  // "_"
        || char === '\u002d';  // "-"
  }

View on GitHub (pinned to c8fc3bf8d3)

Solutions

  1. Inspect the full selector string printed in the message and add the missing closing character (quote, ], =value).
  2. If the selector is built dynamically, log it before the call and assert it is non-empty and well-formed.
  3. Quote attribute values that may be empty or contain spaces: use "value" or 'value' inside [...].
  4. Switch to a literal selector in tests to isolate whether the bug is in the dynamic value or the static structure.

Example fix

// before
const sel = `button[data-test=${id}`;  // missing closing ] when id undefined/truncated
page.locator(sel);

// after
const sel = `button[data-test="${id}"]`;
if (!sel.includes('[]') && !sel.includes('=""'))
  throw new Error(`bad selector: ${sel}`);
page.locator(sel);
Defensive patterns

Strategy: validation

Validate before calling

function assertClosedSelector(sel: string) {
  const open = (sel.match(/[\['"]/g) ?? []).length;
  const close = (sel.match(/[\]'"]/g) ?? []).length;
  if (open !== close) throw new Error(`Selector brackets/quotes unbalanced: ${sel}`);
}
assertClosedSelector(selector);

Type guard

function isValidSelectorStart(sel: string): boolean {
  return typeof sel === 'string' && sel.trim().length > 0;
}

Try / catch

import { InvalidSelectorError } from 'playwright-core';
try {
  await page.locator(sel).click();
} catch (e) {
  if (e instanceof InvalidSelectorError || /Unexpected end of selector/.test(e.message)) {
    logSelectorBuildFailure(sel, e);
    throw new Error(`Refusing to act on malformed selector: ${sel}`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling locator/query APIs with a truncated attribute selector such as `page.locator('button[text=')`, `page.locator('[aria-label')`, or `parseAttributeSelector('div[name="unterminated', false)`. Any input where eat1()/next() reach EOL while skipSpaces/readQuotedString/readOperator/readAttributeToken still expect a closing token.

Common situations: String concatenation that drops a closing bracket or quote; template literals with an undefined variable producing empty fragments; copy-paste of a CSS selector into a Playwright attribute-engine selector expecting quoted values; CI where a selector is built from config and a field is missing.

Related errors


AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12). Data as JSON: /api/errors/3d3632bbf129b588. Report an issue: GitHub.