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
- Re-run the install — the lock is stale and a fresh attempt will usually succeed.
- Serialize browser installs so only one Playwright process holds the lock at a time (queue jobs or use a mutex step).
- Manually remove the lockfile path shown in the message, then re-run 'npx playwright install'.
- 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
- Serialize concurrent Playwright installs sharing one registry directory.
- Give each CI job its own PLAYWRIGHT_BROWSERS_PATH to avoid lock contention.
- Clean up the __dirlock file at the start of a CI step if a prior run may have died.
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
- An active lockfile is found at: ${lockfilePath} Either:
- Executable doesn't exist at ${e} ${wrapInASCIIBox(prettyMess
- WebKit via WSL is only supported on Windows
- Failed to install WebKit via WSL
- ERROR: Playwright does not support installing ${executable.n
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/c63113056a5a9290.
Report an issue: GitHub.