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

  1. Retry the push: the abort happened before any data changed, and lock contention under concurrent writes is expected
  2. Stagger scheduled pushes and discovery so write work and heavy read work do not overlap on the same repository
  3. 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

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


AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21). Data as JSON: /api/errors/f4d56cf0f001bbe2. Report an issue: GitHub.