microsoft/playwright · error · Error

An active lockfile is found at: ${lockfilePath} Either:

Error message

An active lockfile is found at:

  ${lockfilePath}

Either:
- wait a few minutes if other Playwright is installing browsers in parallel
- remove lock manually with:

    ${rmCommand} ${lockfilePath}

<3 Playwright Team

What it means

Thrown from the catch block of Registry.install when the lock acquisition fails with error code ELOCKED — the proper-lockfile library exhausted all 20 retries over ~10 minutes without obtaining the lock. The boxed message tells the user another Playwright process holds the lock and gives the manual removal command for the platform.

Source

Thrown at packages/playwright-core/src/server/registry/index.ts:994

            `requires *removal* of a current installation first.`,
            ``,
            `To *uninstall* current version and re-install latest "${executable.name}":`,
            ``,
            `- Close all running instances of "${executable.name}", if any`,
            `- Use "--force" to install browser:`,
            ``,
            `    ${command}`,
            ``,
            `<3 Playwright Team`,
          ].join('\n'), 1) + '\n\n');
          return;
        }
        await executable._install(!!options?.force);
      }
    } catch (e) {
      if (e.code === 'ELOCKED') {
        const rmCommand = process.platform === 'win32' ? 'rm -R' : 'rm -rf';
        throw new Error('\n' + wrapInASCIIBox([
          `An active lockfile is found at:`,
          ``,
          `  ${lockfilePath}`,
          ``,
          `Either:`,
          `- wait a few minutes if other Playwright is installing browsers in parallel`,
          `- remove lock manually with:`,
          ``,
          `    ${rmCommand} ${lockfilePath}`,
          ``,
          `<3 Playwright Team`,
        ].join('\n'), 1));
      } else {
        throw e;
      }
    } finally {
      if (releaseLock)
        await releaseLock();

View on GitHub (pinned to c8fc3bf8d3)

Solutions

  1. Run the rm command printed in the message ('rm -rf <path>' on macOS/Linux, 'rm -R <path>' on Windows) then re-run the install.
  2. Wait and retry if another install is legitimately running.
  3. Isolate installs with a unique PLAYWRIGHT_BROWSERS_PATH per concurrent job.
  4. Add a lock-cleanup step at the start of CI: remove the __dirlock file before installing.
Defensive patterns

Strategy: retry

Validate before calling

import { existsSync, rmSync } from 'fs';
import { join } from 'path';

// Remove a stale lock before installing
const lock = join(process.env.PLAYWRIGHT_BROWSERS_PATH || '', 'ms-playwright', '__dirlock');
if (existsSync(lock)) rmSync(lock, { recursive: true, force: true });

Try / catch

try {
  await registry.install(executables);
} catch (e) {
  if (e.code === 'ELOCKED' || /active lockfile is found/.test(e.message)) {
    // wait briefly, remove stale lock, retry once
    rmSync(lockfilePath, { recursive: true, force: true });
    await registry.install(executables);
  } else throw e;
}

Prevention

When it happens

Trigger: A prior 'playwright install' crashed without releasing the __dirlock, or a long-running concurrent install still holds it; subsequent installs retry for 10 minutes then surface this error.

Common situations: CI job that was killed mid-install leaving a stale lock; multiple pipeline stages installing browsers into the same PLAYWRIGHT_BROWSERS_PATH simultaneously; local dev interrupted an install with Ctrl-C.

Related errors


AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12). Data as JSON: /api/errors/d56bb1b124128eed. Report an issue: GitHub.