{"record":{"id":"8fedd99205f3225b","repo":"phacility/phabricator","slug":"trying-to-activate-a-resource-from-the-wrong-statu","errorCode":null,"errorMessage":"Trying to activate a resource from the wrong status. Status must be \"%s\", actually \"%s\".","messagePattern":"Trying to activate a resource from the wrong status\\. Status must be \"(.+?)\", actually \"(.+?)\"\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/drydock/storage/DrydockResource.php","lineNumber":198,"sourceCode":"\n    return $this;\n  }\n\n  public function isAllocatedResource() {\n    return $this->isAllocated;\n  }\n\n  public function activateResource() {\n    if (!$this->getID()) {\n      throw new Exception(\n        pht(\n          'Trying to activate a resource which has not yet been persisted.'));\n    }\n\n    $expect_status = DrydockResourceStatus::STATUS_PENDING;\n    $actual_status = $this->getStatus();\n    if ($actual_status != $expect_status) {\n      throw new Exception(\n        pht(\n          'Trying to activate a resource from the wrong status. Status must '.\n          'be \"%s\", actually \"%s\".',\n          $expect_status,\n          $actual_status));\n    }\n\n    $this->openTransaction();\n\n    try {\n      DrydockSlotLock::acquireLocks($this->getPHID(), $this->slotLocks);\n      $this->slotLocks = array();\n    } catch (DrydockSlotLockException $ex) {\n      $this->killTransaction();\n\n      $this->logEvent(\n        DrydockSlotLockFailureLogType::LOGCONST,\n        array(","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/drydock/storage/DrydockResource.php#L180-L216","documentation":"DrydockResource::activateResource() enforces the resource state machine: a resource may only move from STATUS_PENDING to active. The exception names both the expected and actual status, so a mismatch means the resource is already active, broken, released, or destroyed. Most commonly this is a double activation or a resource that jumped straight to active during allocation.","triggerScenarios":"Calling activateResource() twice (e.g. two DrydockResourceUpdateWorker tasks racing or a retry after a partially completed activation); allocating with activateWhenAllocated set so allocateResource() already moved the status to STATUS_ACTIVE, then activating again; activating a resource that a concurrent task broke or released.","commonSituations":"Duplicate resource-update worker tasks after a task retry; a blueprint whose allocateResource() uses ->setActivateWhenAllocated(true) while the standard update worker also activates; stale copies of a resource object in long-running daemon code.","solutions":["Check $resource->getStatus() == DrydockResourceStatus::STATUS_PENDING before calling activateResource(), and skip if it is already STATUS_ACTIVE.","Reload the resource inside the transaction/lock scope right before activating so you see the committed status, not a stale copy.","If using setActivateWhenAllocated(true), do not also run the separate activation step."],"exampleFix":"// before\n$blueprint->activateResource($resource);\n\n// after\nif ($resource->getStatus() === DrydockResourceStatus::STATUS_PENDING) {\n  $blueprint->activateResource($resource);\n}","handlingStrategy":"validation","validationCode":"if ($resource->getStatus() !== DrydockResourceStatus::STATUS_PENDING) {\n  // already active/broken/released: skip or handle\n  return;\n}\n$resource->activateResource();","typeGuard":null,"tryCatchPattern":"try {\n  $resource->activateResource();\n} catch (Exception $ex) {\n  if ($resource->getStatus() === DrydockResourceStatus::STATUS_ACTIVE) {\n    return; // lost activation race; already active\n  }\n  throw $ex;\n}","preventionTips":["Re-read the resource status immediately before transitioning instead of trusting a stale object.","Never combine setActivateWhenAllocated(true) with an explicit activation pass."],"tags":["drydock","php","state-machine","status-transition","resource-lifecycle"],"backgroundTag":"invalid-state-transition","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}