microsoft/playwright · error · Error
No Mobile Safari tabs found at ${this._proxyBase}/json — ope
Error message
No Mobile Safari tabs found at ${this._proxyBase}/json — open Safari first. What it means
After listing tabs from ios_webkit_debug_proxy's /json, WVBrowser._initialize requires at least one debuggable Safari tab to attach to. If the list came back empty (Safari not open, or no tab with a webSocketDebuggerUrl), connection aborts with a directive to open Safari first. This is the most common startup failure for iOS webview automation.
Source
Thrown at packages/playwright-core/src/server/webkit/webview/wvBrowser.ts:210
_page!: WVPage;
constructor(parent: SdkObject, proxyBase: string, headers: { [key: string]: string }, syncServer: SyncServer, directPageTransport: ConnectOverCDPTransport | undefined, options: BrowserOptions) {
super(parent, options);
this._proxyBase = proxyBase;
this._headers = headers;
this._syncServer = syncServer;
this._directPageTransport = directPageTransport;
this._context = new WVBrowserContext(this);
}
async _initialize(): Promise<void> {
await this._context.initialize();
if (this._directPageTransport) {
await this._attachTab('rdp-transport', this._directPageTransport);
} else {
await this._syncTabs();
if (!this._tabs.size)
throw new Error(`No Mobile Safari tabs found at ${this._proxyBase}/json — open Safari first.`);
}
this._page = this._firstTab().page;
}
private _firstTab(): TabEntry {
return this._tabs.values().next().value as TabEntry;
}
async _syncTabs(): Promise<void> {
const tabs = await listTabs(this._proxyBase, this._headers);
const seen = new Set<string>();
for (const tab of tabs) {
const pageId = pageIdFromWsUrl(tab.webSocketDebuggerUrl);
seen.add(pageId);
if (this._tabs.has(pageId))
continue;
try {
await this._attachTab(pageId, new DeferredWebSocketTransport(tab.webSocketDebuggerUrl, this._headers));View on GitHub (pinned to c8fc3bf8d3)
Solutions
- On the device: open Safari and load any page, then retry connectOverCDP.
- Enable Settings > Safari > Advanced > Web Inspector and (if needed) remote automation.
- Ensure the device is unlocked and trusted, and the proxy can still see the tab via /json.
Example fix
// before
// (Safari closed on device)
await webkit.connectOverCDP('http://localhost:27753'); // No Mobile Safari tabs found
// after
// 1. On device: open Safari, navigate to a page.
// 2. Then:
await webkit.connectOverCDP('http://localhost:27753'); Defensive patterns
Strategy: validation
Validate before calling
async function ensureTab(base) {
const tabs = await (await fetch(`${base}/json`)).json();
const usable = tabs.filter(t => !!t.webSocketDebuggerUrl);
if (!usable.length) throw new Error('Open Safari on the device and load a page before connecting.');
}
await ensureTab(endpointBase); Try / catch
try { browser = await webkit.connectOverCDP(base); }
catch (e) {
if (/No Mobile Safari tabs found/i.test(String(e.message))) {
throw new Error('Open Safari and a page on the device, then retry.');
}
throw e;
} Prevention
- Open Safari and navigate to a page before each connectOverCDP.
- Enable Settings > Safari > Advanced > Web Inspector.
- Keep the device unlocked while tests run.
- Verify via /json that a tab with webSocketDebuggerUrl is present.
When it happens
Trigger: Connecting to iOS Safari while Safari has no open tab; Safari open but the page is not debuggable (private browsing, native view); the device locked; web inspector disabled on the device.
Common situations: Forgot to open Safari on the iOS device before connecting; Web Inspector / remote automation disabled in iOS Settings; device screen locked; using a non-Safari WKWebView with no equivalent tab exposed by the proxy.
Related errors
- ios_webkit_debug_proxy ${proxyBase}/json returned ${res.stat
- Not supported
- SyncServer: failed to bind HTTP server
- Cannot set cookies without an open page
- Method not implemented.
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/db3889bebc81dec4.
Report an issue: GitHub.