microsoft/playwright · error · Error
Browser is already in use for ${userDataDir}, use --isolated
Error message
Browser is already in use for ${userDataDir}, use --isolated to run multiple instances of the same browser What it means
Thrown by `createPersistentBrowser` after `isProfileLocked5Times` returns true — meaning the profile's lock file (SingletonLock on Unix, lockfile on Windows) was held by a live process for ~5 seconds of retries. Persistent mode requires exclusive access to the userDataDir, so a locked profile aborts launch. The message directs the user to `--isolated`.
Source
Thrown at packages/playwright-core/src/tools/mcp/browserFactory.ts:164
const playwrightObject = playwright as Playwright;
// Use connectToBrowser instead of playwright[browserName].connect because we don't have browserName.
const browser = await connectToBrowser(playwrightObject, remoteOptions);
browser._connectToBrowserType(playwrightObject[browser._browserName], {}, undefined);
// A browser started via `launchServer` exposes no contexts until one is
// created, so create one when attaching to such a server.
if (!browser.contexts().length)
await browser.newContext(config.browser.contextOptions);
return { browser, browserInfo: browserInfo(browser, config), canBind: false, ownership: 'attached' };
}
async function createPersistentBrowser(config: FullConfig, clientInfo: ClientInfo): Promise<playwrightTypes.Browser> {
testDebug('create browser (persistent)');
const userDataDir = config.browser.userDataDir ?? await createUserDataDir(config, clientInfo);
const tracesDir = await computeTracesDir(config, clientInfo);
if (await isProfileLocked5Times(userDataDir))
throw new Error(`Browser is already in use for ${userDataDir}, use --isolated to run multiple instances of the same browser`);
const browserType = playwright[config.browser.browserName];
const configIgnoreDefaultArgs = config.browser.launchOptions?.ignoreDefaultArgs;
const launchOptions: playwrightTypes.LaunchOptions & playwrightTypes.BrowserContextOptions = {
tracesDir,
...config.browser.launchOptions,
...config.browser.contextOptions,
handleSIGINT: false,
handleSIGTERM: false,
ignoreDefaultArgs: configIgnoreDefaultArgs === true
? true
: [
'--disable-extensions',
...Array.isArray(configIgnoreDefaultArgs) ? configIgnoreDefaultArgs : [],
],
};
try {
const browserContext = await browserType.launchPersistentContext(userDataDir, launchOptions);View on GitHub (pinned to c8fc3bf8d3)
Solutions
- Close the other browser instance using that profile, then retry.
- Use `--isolated` so each session gets its own ephemeral context (no shared userDataDir).
- If the lock is stale (process died), remove the SingletonLock/lockfile under the userDataDir and retry.
- Give each concurrent session a distinct `--user-data-dir` or `--profile`.
Example fix
# before playwright mcp --user-data-dir ~/.cache/mcp-profile # (second concurrent invocation fails) # after playwright mcp --isolated
Defensive patterns
Strategy: validation
Validate before calling
import { isProfileLocked } from '@tools/mcp/browserFactory';
async function assertProfileFree(userDataDir: string) {
if (await isProfileLocked(userDataDir))
throw new Error(`Profile ${userDataDir} is locked by another process; use --isolated.`);
} Try / catch
try {
await launchPersistent(opts);
} catch (e) {
if (/Browser is already in use/.test((e as Error).message)) {
opts.isolated = true; await launchPersistent(opts); // fall back to isolated
} else throw e;
} Prevention
- Use --isolated for concurrent sessions.
- Give each session its own --user-data-dir/--profile.
- Close other browser instances using a shared profile before launching.
When it happens
Trigger: Launching a persistent browser (non-isolated) against a userDataDir already in use by another running browser instance (another MCP/CLI session, a manually-opened Chrome with the same profile, or a prior crashed process whose lock is held). The pre-launch lock check in `isProfileLocked5Times` polls 5x at 1s intervals.
Common situations: Two MCP clients using the same workspace/profile concurrently; a user has Chrome open with that profile; a previous browser process did not clean up its SingletonLock; running on CI where a parallel job shares the profiles dir.
Related errors
- Browser userDataDir is not supported in isolated mode.
- ${err.message} Path: ${lockfilePath}
- An active lockfile is found at: ${lockfilePath} Either:
- Cannot start tracing while stopping
- Cannot start a trace chunk while stopping
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/f3eb29b7680bbd78.
Report an issue: GitHub.