{"record":{"id":"4f657118e5a24da3","repo":"microsoft/playwright","slug":"launching-more-browsers-is-not-allowed","errorCode":null,"errorMessage":"Launching more browsers is not allowed.","messagePattern":"Launching more browsers is not allowed\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/playwright-core/src/server/dispatchers/browserTypeDispatcher.ts","lineNumber":40,"sourceCode":"import type { BrowserType } from '../browserType';\nimport type { RootDispatcher } from './dispatcher';\nimport type * as channels from '../channels';\nimport type { Progress } from '../progress';\n\nexport class BrowserTypeDispatcher extends Dispatcher<BrowserType, channels.BrowserTypeChannel, RootDispatcher> implements channels.BrowserTypeChannel {\n  _type_BrowserType = true;\n  private readonly _denyLaunch: boolean;\n  constructor(scope: RootDispatcher, browserType: BrowserType, denyLaunch: boolean) {\n    super(scope, browserType, 'BrowserType', {\n      executablePath: browserType.executablePath(),\n      name: browserType.name()\n    });\n    this._denyLaunch = denyLaunch;\n  }\n\n  async launch(params: channels.BrowserTypeLaunchParams, progress: Progress): Promise<channels.BrowserTypeLaunchResult> {\n    if (this._denyLaunch)\n      throw new Error(`Launching more browsers is not allowed.`);\n\n    const browser = await this._object.launch(progress, params);\n    return { browser: new BrowserDispatcher(this, browser) };\n  }\n\n  async launchPersistentContext(params: channels.BrowserTypeLaunchPersistentContextParams, progress: Progress): Promise<channels.BrowserTypeLaunchPersistentContextResult> {\n    if (this._denyLaunch)\n      throw new Error(`Launching more browsers is not allowed.`);\n\n    const browserContext = await this._object.launchPersistentContext(progress, params.userDataDir, params);\n    const browserDispatcher = new BrowserDispatcher(this, browserContext._browser);\n    const contextDispatcher = BrowserContextDispatcher.from(browserDispatcher, browserContext);\n    return { browser: browserDispatcher, context: contextDispatcher };\n  }\n\n  async connectOverCDP(params: channels.BrowserTypeConnectOverCDPParams, progress: Progress): Promise<channels.BrowserTypeConnectOverCDPResult> {\n    if (this._denyLaunch)\n      throw new Error(`Launching more browsers is not allowed.`);","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/microsoft/playwright/blob/c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6/packages/playwright-core/src/server/dispatchers/browserTypeDispatcher.ts#L22-L58","documentation":"Thrown by BrowserTypeDispatcher.launch() when _denyLaunch is true. The Playwright server (playwrightServer / launchServer / connect / preLaunchedBrowser modes) sets denyLaunch=true on the BrowserTypeDispatcher once the server itself owns browser lifecycle, so clients cannot spawn additional browsers. This is the launch path (non-persistent).","triggerScenarios":"Calling chromium.launch() / firefox.launch() / webkit.launch() over a connection to a Playwright server whose initialize result carried denyLaunch=true (launchServer mode, connect mode, preLaunchedBrowser mode, or launchServerShared). The check fires immediately before any browser process starts.","commonSituations":"Connecting to a remote browser server (playwright.launchServer / browserType.connectOverCDP to a managed endpoint) and then calling launch() again from the client; MCP/remote sessions that already receive a preLaunchedBrowser but still try to spawn their own; misreading 'connect' as 'launch'.","solutions":["Use the browser the server already gave you: read preLaunchedBrowser from the init result instead of calling launch().","If you need the client to launch, run against a plain local playwright instance rather than a denyLaunch server endpoint.","Confirm the connection mode you are using (connect/launchServer/preLaunched) and align expectations: only the non-denyLaunch path allows launch()."],"exampleFix":"// before: launch over a managed server connection\nconst browser = await chromium.connect(wsEndpoint);\nconst extra = await chromium.launch(); // denied\n\n// after: reuse the server-provided browser\nconst { browser } = await chromium.connect(wsEndpoint);\nconst context = await browser.newContext();","handlingStrategy":"validation","validationCode":"const init = await playwright.initialize();\nif (init.denyLaunch) throw new Error('Server denies launch(); use init.preLaunchedBrowser instead');","typeGuard":"function hasPreLaunchedBrowser(init: any): init is { preLaunchedBrowser: Browser } {\n  return !!init?.preLaunchedBrowser;\n}","tryCatchPattern":"try {\n  await chromium.launch();\n} catch (e) {\n  if (/Launching more browsers is not allowed/.test(e.message)) { /* use preLaunchedBrowser */ }\n  else throw e;\n}","preventionTips":["Read the init/denyLaunch state once at connect time and branch client logic on it.","Treat a managed server connection as 'reuse, do not launch'.","Run launches from local playwright when you need spawn control."],"tags":["deny-launch","server","browser-type","remote","launch"],"backgroundTag":null,"analyzedSha":"c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6","analyzedAt":"2026-08-12T07:26:36.950Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}