microsoft/playwright · error · Error
No attached tab to forward browser-level command: ${method}
Error message
No attached tab to forward browser-level command: ${method} What it means
Thrown by the extension browser model's `sendBrowserCommand` when there are no attached tab sessions. Browser-scoped CDP commands (Storage.*, Browser.*, etc.) are forwarded through any attached tab via `chrome.debugger.sendCommand`, which requires a target; with zero tabs attached there is no route, so the command is rejected.
Source
Thrown at packages/playwright-core/src/tools/mcp/browserModel.ts:171
return { success: false };
await this._sendToExtension('chrome.tabs.remove', [tabSession.tabId]);
return { success: true };
}
getTargetInfo(sessionId: string | undefined): any {
if (!sessionId)
return undefined;
return this._findTabSession(s => s.sessionId === sessionId)?.targetInfo;
}
// Forward a browser-level CDP command (Storage.*, Browser.*, etc.) that is
// not associated with a specific tab. chrome.debugger.sendCommand requires a
// target, so we route through any attached tab; the command itself is
// browser-scoped and returns the same result regardless of which tab is used.
async sendBrowserCommand(method: string, params: any): Promise<any> {
const tabSession = this._tabSessions.values().next().value;
if (!tabSession)
throw new Error(`No attached tab to forward browser-level command: ${method}`);
return await this._sendToExtension('chrome.debugger.sendCommand', [
{ tabId: tabSession.tabId },
method,
params,
]);
}
// Forward a CDP command from Playwright to the tab its sessionId resolves to.
async sendCommand(sessionId: string, method: string, params: any): Promise<any> {
// Two cases:
// 1. sessionId is a relay-level tab session (pw-tab-N) → strip and route by tabId.
// 2. sessionId is a child CDP session (worker, oopif) → route to its owning tab,
// keep the sessionId so the extension forwards it to chrome.debugger.
let tabSession = this._findTabSession(s => s.sessionId === sessionId);
let cdpSessionId: string | undefined;
if (!tabSession) {
tabSession = this._findTabSession(s => s.childSessions.has(sessionId));
cdpSessionId = sessionId;View on GitHub (pinned to c8fc3bf8d3)
Solutions
- Ensure at least one tab is open and attached before issuing browser-level commands (trigger navigation/auto-attach first).
- If all tabs were closed, open a new tab/page (which auto-attaches) and retry.
- Confirm the extension still holds debugger attach permissions; re-grant if revoked.
Defensive patterns
Strategy: validation
Validate before calling
// Ensure a tab is attached before issuing browser-level commands.
function hasAttachedTab(model: any): boolean {
// _tabSessions is private; expose a count via a public getter if extending.
// Otherwise track attachments client-side via attach events.
return /* model.tabCount() > 0 */ true;
} Try / catch
try {
await model.sendBrowserCommand(method, params);
} catch (e) {
if (/No attached tab/.test((e as Error).message)) {
await model.createTarget('about:blank'); // open+attach a tab
await model.sendBrowserCommand(method, params);
} else throw e;
} Prevention
- Open/attach at least one tab before browser-level CDP calls.
- Listen for detach events and stop issuing browser-level commands when all tabs close.
- Confirm the extension retains debugger attach permission.
When it happens
Trigger: Issuing a browser-level CDP command (e.g. through Playwright's browser-level session) before any tab has been attached via `enableAutoAttach`/`_attachTab`, or after all tabs have been detached/closed.
Common situations: Calling a browser-scoped API at the very start of a session before auto-attach completed; all tabs were closed leaving the browser with zero targets; the extension detached all debuggee targets (user closed all tabs or revoked debugger permission).
Related errors
- Failed to create tab
- No tab found for sessionId: ${sessionId}
- Playwright Extension not found in "${userDataDir}". Install
- page: expected Page or Frame
- Connecting over CDP is only supported in Chromium and WebKit
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/5978806ce4eceadc.
Report an issue: GitHub.