microsoft/playwright · error · Error

${err.message} Path: ${lockfilePath}

Error message

${err.message} Path: ${lockfilePath}

What it means

Thrown from the onCompromised callback of the proper-lockfile lock() acquired during Registry.install. The underlying lock library reports the lock as 'compromised' — the lockfile/lockdir was removed or overwritten by another process while this install still believed it held the lock. Playwright re-wraps that error and appends the lockfilePath so the offending file is identifiable.

Source

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

  async install(executablesToInstall: Executable[], options?: { force?: boolean, gc?: boolean }) {
    const executables = this._dedupe(executablesToInstall);
    await fs.promises.mkdir(registryDirectory, { recursive: true });
    const lockfilePath = path.join(registryDirectory, '__dirlock');
    const linksDir = path.join(registryDirectory, '.links');

    let releaseLock;
    try {
      releaseLock = await lock(registryDirectory, {
        retries: {
          // Retry 20 times during 10 minutes with
          // exponential back-off.
          // See documentation at: https://www.npmjs.com/package/retry#retrytimeoutsoptions
          retries: 20,
          factor: 1.27579,
        },
        onCompromised: (err: Error) => {
          throw new Error(`${err.message} Path: ${lockfilePath}`);
        },
        lockfilePath,
      });
      // Create a link first, so that cache validation does not remove our own browsers.
      await fs.promises.mkdir(linksDir, { recursive: true });
      await fs.promises.writeFile(path.join(linksDir, calculateSha1(PACKAGE_PATH)), PACKAGE_PATH);

      // Remove stale browsers.
      if (options?.gc !== false && !getAsBooleanFromENV('PLAYWRIGHT_SKIP_BROWSER_GC'))
        await this._validateInstallationCache(linksDir);

      // Install browsers for this package.
      for (const executable of executables) {
        if (!executable._install)
          throw new Error(`ERROR: Playwright does not support installing ${executable.name}`);

        if (!getAsBooleanFromENV('CI') && !executable._isHermeticInstallation && !options?.force && executable.executablePath()) {
          const { embedderName } = getEmbedderName();

View on GitHub (pinned to c8fc3bf8d3)

Solutions

  1. Re-run the install — the lock is stale and a fresh attempt will usually succeed.
  2. Serialize browser installs so only one Playwright process holds the lock at a time (queue jobs or use a mutex step).
  3. Manually remove the lockfile path shown in the message, then re-run 'npx playwright install'.
  4. Set PLAYWRIGHT_BROWSERS_PATH to isolate installs per job/agent so they no longer contend.
Defensive patterns

Strategy: retry

Try / catch

async function safeInstall(executables, options) {
  for (let attempt = 0; attempt < 3; attempt++) {
    try { return await registry.install(executables, options); }
    catch (e) {
      if (/Path:/.test(e.message) && attempt < 2) continue;
      throw e;
    }
  }
}

Prevention

When it happens

Trigger: An external process (another Playwright install, a cleanup script, a user) deletes or overwrites the __dirlock file under the registry directory while an install is in progress and still within its retry window; or two concurrent installs race and one invalidates the other's lock.

Common situations: Parallel 'npm install' / 'playwright install' invocations in the same CI job sharing one registry directory; a Docker build cache wipe mid-install; antivirus or a tmp-cleanup daemon removing the lock.

Related errors


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