{"record":{"id":"97271d8fffe7d0f5","repo":"microsoft/playwright","slug":"malformed-endpoint-did-you-use-browsertype-launch","errorCode":null,"errorMessage":"Malformed endpoint. Did you use BrowserType.launchServer method?","messagePattern":"Malformed endpoint\\. Did you use BrowserType\\.launchServer method\\?","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/playwright-core/src/client/connect.ts","lineNumber":61,"sourceCode":"  connection.on('close', () => {\n    // Emulate all pages, contexts and the browser closing upon disconnect.\n    for (const context of browser?.contexts() || []) {\n      for (const page of context.pages())\n        page._onClose();\n      context._onClose();\n    }\n    setTimeout(() => browser?._didClose(), 0);\n  });\n\n  const result = await raceAgainstDeadline(async () => {\n    // For tests.\n    if ((params as any).__testHookBeforeCreateBrowser)\n      await (params as any).__testHookBeforeCreateBrowser();\n\n    const playwright = await connection!.initializePlaywright();\n    if (!playwright._initializer.preLaunchedBrowser) {\n      connection.close();\n      throw new Error('Malformed endpoint. Did you use BrowserType.launchServer method?');\n    }\n    playwright.selectors = playwright.selectors;\n    browser = Browser.from(playwright._initializer.preLaunchedBrowser!);\n    browser._shouldCloseConnectionOnClose = true;\n    browser.on(Events.Browser.Disconnected, () => connection.close());\n    return browser;\n  }, deadline);\n  if (!result.timedOut) {\n    return result.result;\n  } else {\n    connection.close();\n    throw new Error(`Timeout ${params.timeout}ms exceeded`);\n  }\n}\n\nexport async function connectToEndpoint(parentConnection: Connection, params: channels.LocalUtilsConnectParams, timeout: channels.TimeoutOptions): Promise<Connection> {\n  const localUtils = parentConnection.localUtils();\n  const transport = localUtils ? new JsonPipeTransport(localUtils) : new WebSocketTransport();","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/microsoft/playwright/blob/c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6/packages/playwright-core/src/client/connect.ts#L43-L79","documentation":"Thrown by connectToEndpoint after the WebSocket handshake succeeds and Playwright is initialized, but playwright._initializer.preLaunchedBrowser is absent. browserType.connect() expects a server that was started with browserType.launchServer(), which pre-launches a browser and ships its reference in the initializer. The endpoint you reached is a valid Playwright server but not one that exposes a pre-launched browser.","triggerScenarios":"Calling chromium.firefox.webkit.connect({ wsEndpoint }) against: (a) a raw browser CDP/WebSocket endpoint, (b) a server started via `playwright launch-server` without launchServer() in code, (c) a playwright codegen/inspector server, or (d) any endpoint where the server did not call launchServer({ wsEndpoint }). initializePlaywright() resolves, but the initializer lacks preLaunchedBrowser, so the client closes the connection and throws.","commonSituations":"Pointing connect() at a Chrome DevTools Protocol target (you want connectOverCDP instead); version skew where the server is an older/newer build that does not populate preLaunchedBrowser; connecting to an orchestrator that proxies WebSocket but strips the browser initializer; copy-pasting a wsEndpoint from launch() instead of launchServer().","solutions":["Start the server with browserType.launchServer({ wsEndpoint, host, port }) (or `playwright launch-server chromium`) and connect to the wsEndpoint it prints.","If the target is a raw Chrome/Edge CDP endpoint (e.g. --remote-debugging-port=9222), use browserType.connectOverCDP(httpUrl) instead of connect().","Verify the server log actually prints 'Listening at ws://...' from launchServer; if not, switch to launchServer.","Ensure client and server run the same Playwright version to avoid an empty/missing preLaunchedBrowser initializer."],"exampleFix":"// before\nconst browser = await chromium.connect({ wsEndpoint: 'ws://localhost:9222/devtools/browser/...' });\n\n// after — server side\nconst server = await chromium.launchServer({ host: '127.0.0.1', port: 9333 });\nconsole.log(server.wsEndpoint());\n// client side\nconst browser = await chromium.connect({ wsEndpoint: server.wsEndpoint() });\n// — or, for a raw CDP target —\nconst browser = await chromium.connectOverCDP('http://localhost:9222');","handlingStrategy":"validation","validationCode":"// Before connect(), confirm the endpoint is a launchServer endpoint.\n// launchServer endpoints respond to the Playwright protocol with a preLaunchedBrowser initializer.\n// Quick reachability + identity check (does NOT prove launchServer, but catches CDP/raw WS):\nasync function isPlaywrightServer(wsEndpoint) {\n  const { WebSocket } = await import('ws');\n  return await new Promise(resolve => {\n    const ws = new WebSocket(wsEndpoint);\n    const t = setTimeout(() => { ws.terminate(); resolve(false); }, 5000);\n    ws.on('open', () => { clearTimeout(t); ws.close(); resolve(true); });\n    ws.on('error', () => { clearTimeout(t); resolve(false); });\n  });\n}\nif (!(await isPlaywrightServer(wsEndpoint))) throw new Error('Use connectOverCDP for raw CDP, or launchServer() on the server.');","typeGuard":"import type { Browser, BrowserType } from 'playwright-core';\n\n// launchServer is the producer; its return type is the proof.\nasync function assertLaunchServer(bt: BrowserType, opts: Parameters<BrowserType['launchServer']>[0]): Promise<string> {\n  const s = await bt.launchServer(opts);\n  return s.wsEndpoint(); // only launchServer exposes wsEndpoint() on a BrowserServer\n}","tryCatchPattern":"try {\n  browser = await chromium.connect({ wsEndpoint, timeout: 30_000 });\n} catch (e) {\n  if (/Malformed endpoint\\. Did you use BrowserType\\.launchServer method\\?/.test(String(e?.message))) {\n    // Distinguish raw CDP from a genuinely wrong server before retrying.\n    browser = await chromium.connectOverCDP(wsEndpoint.replace(/^ws/, 'http'));\n  } else throw e;\n}","preventionTips":["Always obtain wsEndpoint from launchServer().wsEndpoint(); never hand-write it.","Document at the call site which producer (launchServer vs CDP vs codegen) the endpoint came from.","Pin client and server Playwright versions in lockfile."],"tags":["network","connection","launchserver","configuration"],"backgroundTag":null,"analyzedSha":"c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6","analyzedAt":"2026-08-12T07:26:36.950Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}