{"record":{"id":"ec6d6789b3846826","repo":"phacility/phabricator","slug":"trying-to-allocate-a-resource-from-the-wrong-statu","errorCode":null,"errorMessage":"Trying to allocate a resource from the wrong status. Status must be \"%s\", actually \"%s\".","messagePattern":"Trying to allocate 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":131,"sourceCode":"    $this->slotLocks[] = $key;\n    return $this;\n  }\n\n  public function allocateResource() {\n    // We expect resources to have a pregenerated PHID, as they should have\n    // been created by a call to DrydockBlueprint->newResourceTemplate().\n    if (!$this->getPHID()) {\n      throw new Exception(\n        pht(\n          'Trying to allocate a resource with no generated PHID. Use \"%s\" to '.\n          'create new resource templates.',\n          'newResourceTemplate()'));\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 allocate a resource from the wrong status. Status must '.\n          'be \"%s\", actually \"%s\".',\n          $expect_status,\n          $actual_status));\n    }\n\n    if ($this->activateWhenAllocated) {\n      $new_status = DrydockResourceStatus::STATUS_ACTIVE;\n    } else {\n      $new_status = DrydockResourceStatus::STATUS_PENDING;\n    }\n\n    $this->openTransaction();\n\n    try {\n      DrydockSlotLock::acquireLocks($this->getPHID(), $this->slotLocks);\n      $this->slotLocks = array();","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/drydock/storage/DrydockResource.php#L113-L149","documentation":"allocateResource() only accepts resources in STATUS_PENDING — the status newResourceTemplate() assigns. Any other status means the object already entered (or was pulled out of) the lifecycle: re-allocating an ACTIVE resource, allocating one manually set to BROKEN/RELEASED, or reusing a resource object whose allocation already ran will throw. The guard keeps the PENDING → (ACTIVE|PENDING) transition in allocateResource() unambiguous.","triggerScenarios":"Calling allocateResource() twice on the same template object after the first call saved/activated it; setting a custom status on the resource before allocating; loading an existing resource from the database and trying to push it back through allocation.","commonSituations":"Retry logic in custom blueprints that re-enters allocation after a partial failure without rebuilding the template; copy-paste blueprint code that mutates status; migration scripts trying to 're-allocate' old resources.","solutions":["Allocate each template exactly once; on failure, build a fresh template with newResourceTemplate() and retry","Do not pre-set the resource status — newResourceTemplate() already sets STATUS_PENDING","To reactivate an existing resource, use the resource update worker path, not allocateResource()","Assert status is PENDING before calling allocateResource() in custom code to fail with a clearer trace"],"exampleFix":"// before\n$resource = $this->newResourceTemplate($blueprint);\ntry {\n  $resource->allocateResource();\n} catch (Exception $ex) {\n  $resource->allocateResource(); // second attempt on same object\n}\n// Exception: Trying to allocate a resource from the wrong status...\n\n// after\ntry {\n  $resource = $this->newResourceTemplate($blueprint);\n  $resource->allocateResource();\n} catch (Exception $ex) {\n  $resource = $this->newResourceTemplate($blueprint); // fresh PENDING template\n  $resource->allocateResource();\n}","handlingStrategy":"validation","validationCode":"// Assert PENDING status before allocating:\nif ($resource->getStatus() !== DrydockResourceStatus::STATUS_PENDING) {\n  // already advanced or terminal: build a fresh template instead\n  $resource = $this->newResourceTemplate($blueprint);\n}\n$resource->allocateResource();","typeGuard":"function isFreshResourceTemplate(DrydockResource $resource) {\n  return $resource->getStatus() === DrydockResourceStatus::STATUS_PENDING\n    && (bool)$resource->getPHID();\n}","tryCatchPattern":"catch (Exception $ex) { on 'from the wrong status', discard the current object and rebuild via newResourceTemplate() before retrying; do not retry on the same object }","preventionTips":["Allocate each template exactly once; build a new template per retry attempt","Never pre-set resource status before allocateResource()","For reactivating existing resources use the resource update worker, never re-allocation"],"tags":["drydock","phabricator","resource","state-machine","double-allocate","blueprint"],"backgroundTag":"invalid-state-transition","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}