microsoft/playwright · error · InvalidSelectorError
Composite locators are not supported with piercing frames, w
Error message
Composite locators are not supported with piercing frames, while querying "${locator}" What it means
When pierce-frames mode is active (browserContext option pierceFrames, or internal piercing), composite (multi-part chained) locators are not supported. If a nested selector part is encountered while pierce is on, InvalidSelectorError is thrown.
Source
Thrown at packages/playwright-core/src/server/frameSelectors.ts:134
const frameSeq = +match[1];
const jumptToFrame = this.frame._page.frameManager.frames().find(frame => frame.seq === frameSeq);
if (!jumptToFrame)
throw new InvalidSelectorError(`Invalid frame in aria-ref selector "${selector}"`);
return jumptToFrame;
}
private async _resolveFramesForSelector(selector: string, options: types.StrictOptions & { noDefaultPierce?: boolean } = {}, scope?: ElementHandle): Promise<SelectorInFrame[]> {
const pierceByDefault = !!this.frame._page.browserContext._options.pierceFrames && !options.noDefaultPierce;
const { pierce, chunks } = splitSelectorByFrame(selector, pierceByDefault);
for (const chunk of chunks) {
visitAllSelectorParts(chunk, (part, nested) => {
if (nested && part.name === 'internal:control' && part.body === 'enter-frame') {
const locator = asLocator(this.frame._page.browserContext._browser.sdkLanguage(), selector);
throw new InvalidSelectorError(`Frame locators are not allowed inside composite locators, while querying "${locator}"`);
}
if (nested && pierce) {
const locator = asLocator(this.frame._page.browserContext._browser.sdkLanguage(), selector);
throw new InvalidSelectorError(`Composite locators are not supported with piercing frames, while querying "${locator}"`);
}
});
}
if (pierce) {
const parsed = chunks[0]; // Only one chunk is allowed with pierce, it may contain enter-frame parts.
if (parsed.parts.some((part, index) => part.name === 'nth' && index !== parsed.parts.length - 1)) {
const locator = asLocator(this.frame._page.browserContext._browser.sdkLanguage(), selector);
throw new InvalidSelectorError(`nth can only be the last locator when piercing frames, while querying "${locator}"`);
}
return await this._resolveFramePiercingSelector(parsed, options, scope);
}
const result = await this._resolveChainedSelector(selector, options, chunks, scope);
return result ? [result] : [];
}
private async _resolveChainedSelector(selector: string, options: types.StrictOptions, frameChunks: ParsedSelector[], scope: ElementHandle | undefined): Promise<SelectorInFrame | null> {View on GitHub (pinned to c8fc3bf8d3)
Solutions
- Disable pierceFrames if you need composite locators, or
- Simplify the locator to a single-part selector when piercing is enabled.
- Refactor the query into a frameLocator chain that does not produce nested composite parts.
Example fix
// before
const ctx = await browser.newContext({ pierceFrames: true });
await page.locator('div >> button').click(); // composite under pierce -> throws
// after
await page.locator('button').click(); Defensive patterns
Strategy: validation
Validate before calling
// Avoid composite (>>) selectors when piercing is on
const isPiercing = !!context.options()?.pierceFrames;
if (isPiercing && sel.includes('>>')) throw new Error('no composite under pierce'); Type guard
null
Try / catch
null
Prevention
- Decide between pierceFrames and composite locators up front; do not mix.
- Document the piercing mode in test fixtures so contributors use single-part locators.
When it happens
Trigger: Enabling pierceFrames on a BrowserContext (or using piercing selectors) and then issuing a composite/chained locator that has nested parts, which the piercing resolver cannot decompose.
Common situations: Turning on pierceFrames experimentally and reusing existing composite locators; frameworks that auto-generate chained selectors; refactoring tests without re-validating against piercing.
Related errors
- Error while parsing selector `${selector}` - selector cannot
- Frame locators are not allowed inside composite locators, wh
- nth can only be the last locator when piercing frames, while
- Pierce-frame mode matched elements from multiple frames.
- options.visibility is not supported, did you mean options.st
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/dfc166c3688f9f2f.
Report an issue: GitHub.