phacility/phabricator · error · Exception
Trying to acquire a lease on a resource which is in the…
Error message
Trying to acquire a lease on a resource which is in the wrong state: status must be "%s", actually "%s".
What it means
DrydockLease::acquireOnResource() is the single entry point that moves a lease from PENDING onto a resource, and its precondition is that the lease status is still STATUS_PENDING. Any other status (RELEASED, ACTIVE, ACQUIRED, BROKEN...) means the lease already went through (or skipped) part of its lifecycle, so the state machine refuses with this Exception. This is a programmer/state-machine error, not a transient condition — retrying the same call on the same lease object will fail identically.
Solutions
- Reload the lease from the database immediately before acquiring and confirm status is still DrydockLeaseStatus::STATUS_PENDING
- Make sure you acquire each lease exactly once — follow the pattern in DrydockLeaseUpdateWorker::acquireLease()
- If the lease already moved to ACQUIRED, call activateOnResource() instead; if RELEASED/BROKEN, create a new lease
- Guard custom allocator code against double-entry (yield/retry with a fresh load rather than reusing the in-memory object)
Example fix
// before
$lease->acquireOnResource($resource);
// possibly: status must be "pending", actually "acquired"
// after
$lease = id(new DrydockLeaseQuery())
->setViewer($viewer)
->withPHIDs(array($lease->getPHID()))
->executeOne();
if ($lease->getStatus() !== DrydockLeaseStatus::STATUS_PENDING) {
return; // already advanced by another worker
}
$lease->acquireOnResource($resource); Defensive patterns
Strategy: validation
Validate before calling
// Assert lease is still PENDING immediately before acquiring:
$lease = id(new DrydockLeaseQuery())
->setViewer($viewer)
->withPHIDs(array($lease->getPHID()))
->executeOne();
if ($lease->getStatus() !== DrydockLeaseStatus::STATUS_PENDING) {
// another worker advanced it; skip, don't acquire
}
$lease->acquireOnResource($resource); Try / catch
catch (Exception $ex) { on 'status must be "pending"', reload the lease: if ACQUIRED continue to activation, if ACTIVE it is done, otherwise (RELEASED/BROKEN) abandon and create a new lease } Prevention
- Never call acquireOnResource() twice on the same lease; model retry as reload-then-decide
- Follow the worker's acquireLease() pattern in custom allocator code
- Keep allocation decisions on fresh database loads, not cached objects, in concurrent contexts
When it happens
Trigger: Calling acquireOnResource() twice on the same lease object (double allocation in custom allocator code); acquiring a lease that a worker already acquired concurrently; acquiring a lease loaded in a stale state after another process released it.
Common situations: Custom blueprint implementations or Drydock extensions that hand-roll the allocation sequence; retry logic that re-enters acquire with the same lease after a partial failure; reusing a lease object fetched before a daemon processed it.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Trying to activate a lease which has the wrong status…
- Blueprint " " (of type " ") is not properly implemented: it…
- Blueprint " " (of type " ") is not properly implemented: it…
- Diff (" ") has wrong revision ID (" ", expected " ").
- Failed to acquire lock for resource
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/9496e5ba0b759a0f.
Report an issue: GitHub.
Appendix: source
Thrown at src/applications/drydock/storage/DrydockLease.php:220
return $this;
}
public function setActivateWhenAcquired($activate) {
$this->activateWhenAcquired = true;
return $this;
}
public function needSlotLock($key) {
$this->slotLocks[] = $key;
return $this;
}
public function acquireOnResource(DrydockResource $resource) {
$expect_status = DrydockLeaseStatus::STATUS_PENDING;
$actual_status = $this->getStatus();
if ($actual_status != $expect_status) {
throw new Exception(
pht(
'Trying to acquire a lease on a resource which is in the wrong '.
'state: status must be "%s", actually "%s".',
$expect_status,
$actual_status));
}
if ($this->activateWhenAcquired) {
$new_status = DrydockLeaseStatus::STATUS_ACTIVE;
} else {
$new_status = DrydockLeaseStatus::STATUS_ACQUIRED;
}
if ($new_status == DrydockLeaseStatus::STATUS_ACTIVE) {
if ($resource->getStatus() == DrydockResourceStatus::STATUS_PENDING) {
throw new Exception(
pht(
'Trying to acquire an active lease on a pending resource. '.View on GitHub (pinned to 5720a38cfe)