phacility/phabricator · error · PhutilProxyException
Failed to acquire write lock after waiting %s second(s). You
Error message
Failed to acquire write lock after waiting %s second(s). You may be able to retry later. (%s)
What it means
Before a push (write) can proceed, the engine acquires the repository's global write lock with a bounded wait; a PhutilLockException timeout is wrapped in a PhutilProxyException that preserves the wait budget and the lock hint. Another device or daemon held the write lock longer than the wait budget, so the write was aborted before any mutation began.
Source
Thrown at src/applications/diffusion/protocol/DiffusionRepositoryClusterEngine.php:382
// Wait a little longer before the next message we print.
$step_wait = $step_wait + 0.5;
$step_wait = min($step_wait, 3);
}
$waited = (PhabricatorTime::getNow() - $start);
if ($waited) {
$this->logLine(
pht(
'Acquired write lock after %s second(s).',
new PhutilNumber($waited)));
} else {
$this->logLine(
pht(
'Acquired write lock immediately.'));
}
} catch (PhutilLockException $ex) {
throw new PhutilProxyException(
pht(
'Failed to acquire write lock after waiting %s second(s). You '.
'may be able to retry later. (%s)',
new PhutilNumber($lock_wait),
$ex->getHint()),
$ex);
}
$versions = PhabricatorRepositoryWorkingCopyVersion::loadVersions(
$repository_phid);
foreach ($versions as $version) {
if (!$version->getIsWriting()) {
continue;
}
throw new Exception(
pht(
'An previous write to this repository was interrupted; refusing '.View on GitHub (pinned to 5720a38cfe)
Solutions
- Retry the push: the abort happened before any data changed, and lock contention under concurrent writes is expected
- Stagger scheduled pushes and discovery so write work and heavy read work do not overlap on the same repository
- If pushes consistently fail, locate the stuck lock holder via daemon logs and bin/phd status, and restart that daemon to clear a leaked lock
Defensive patterns
Strategy: retry
Try / catch
$attempts = 3;
for ($i = 0; $i < $attempts; $i++) {
try {
return $engine->synchronizeWorkingCopyBeforeWrite();
} catch (PhutilProxyException $ex) {
if (!($ex->getPrevious() instanceof PhutilLockException)) {
throw $ex;
}
sleep(5 * (2 ** $i));
}
}
// surface a 'repository busy, push aborted before any changes' error to the pusher
throw $ex; Prevention
- Stagger CI pushes so concurrent writers do not fight for the write lock
- Keep heavy pulls/discovery off push windows for large repositories
- Restart daemons that leak write locks rather than letting pushes fail forever
When it happens
Trigger: A push arrives while another device's push, or a long-running sync/pull, holds the repository write lock; the losing writer times out. Frequently seen with CI systems pushing to clustered repositories.
Common situations: Frequent pushes from multiple cluster nodes; large pushes competing with heavy pulls; stale write locks after a daemon crash; manual bin/repository commands overlapping with push traffic.
Related errors
- Failed to acquire read lock after waiting %s second(s). You
- Unable to acquire slot locks: %s.
- Trying to refund a charge which is already refunding!
- This host has device ID "%s", but there is no corresponding
- Configuration file specifies cluster peer ("%s", at index "%
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/f4d56cf0f001bbe2.
Report an issue: GitHub.