{"record":{"id":"307bd8481e43f9be","repo":"phacility/phabricator","slug":"blueprint-s-of-type-s-is-not-properly-impl-307bd8","errorCode":null,"errorMessage":"Blueprint \"%s\" (of type \"%s\") is not properly implemented: it returned from \"%s\" with a lease acquired on the wrong resource.","messagePattern":"Blueprint \"(.+?)\" \\(of type \"(.+?)\"\\) is not properly implemented: it returned from \"(.+?)\" with a lease acquired on the wrong resource\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/drydock/worker/DrydockLeaseUpdateWorker.php","lineNumber":959,"sourceCode":"    DrydockBlueprint $blueprint,\n    DrydockResource $resource,\n    DrydockLease $lease) {\n\n    if (!$lease->isAcquiredLease()) {\n      throw new Exception(\n        pht(\n          'Blueprint \"%s\" (of type \"%s\") is not properly implemented: it '.\n          'returned from \"%s\" without acquiring a lease.',\n          $blueprint->getBlueprintName(),\n          $blueprint->getClassName(),\n          'acquireLease()'));\n    }\n\n    $lease_phid = $lease->getResourcePHID();\n    $resource_phid = $resource->getPHID();\n\n    if ($lease_phid !== $resource_phid) {\n      throw new Exception(\n        pht(\n          'Blueprint \"%s\" (of type \"%s\") is not properly implemented: it '.\n          'returned from \"%s\" with a lease acquired on the wrong resource.',\n          $blueprint->getBlueprintName(),\n          $blueprint->getClassName(),\n          'acquireLease()'));\n    }\n  }\n\n\n/* -(  Activating Leases  )-------------------------------------------------- */\n\n\n  /**\n   * @task activate\n   */\n  private function activateLease(DrydockLease $lease) {\n    $resource = $lease->getResource();","sourceCodeStart":941,"sourceCodeEnd":977,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/drydock/worker/DrydockLeaseUpdateWorker.php#L941-L977","documentation":"validateAcquiredLease() also checks that the acquired lease's resourcePHID equals the PHID of the resource it was acquired against. A mismatch means the blueprint acquired the lease on a different resource than the one the worker selected, breaking the pairing between lease and resource. The blueprint must acquire on exactly the $resource passed in.","triggerScenarios":"Blueprint acquireLease() that loads its own resource (e.g. by attribute lookup or getBlueprint() query) and calls acquireLease() on that object instead of the passed $resource; reusing a cached resource object from a previous allocation.","commonSituations":"Blueprint queries for 'a free host' internally rather than using the resource the allocator chose; copied code from a single-resource blueprint where hardcoding happened to work.","solutions":["Use the $resource parameter passed to acquireLease(); do not reload or re-select a resource inside the blueprint.","If the blueprint needs related objects, attach them to the passed resource instead of substituting another one.","Assert $lease->getResourcePHID() === $resource->getPHID() in development builds."],"exampleFix":"// before\npublic function acquireLease(DrydockResource $resource, DrydockLease $lease) {\n  $host = $this->loadAnyHostResource(); // different resource!\n  $host->acquireLease($lease);\n}\n\n// after\npublic function acquireLease(DrydockResource $resource, DrydockLease $lease) {\n  $resource->acquireLease($lease);\n}","handlingStrategy":"validation","validationCode":"if ($lease->getResourcePHID() !== $resource->getPHID()) {\n  throw new Exception(\n    pht('Lease acquired on resource \"%s\", expected \"%s\".',\n      $lease->getResourcePHID(), $resource->getPHID()));\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always acquire on the $resource parameter passed into blueprint acquireLease().","Never reload or re-select resources inside acquireLease(); the allocator owns that choice."],"tags":["drydock","php","blueprint","contract","lease","object-reference"],"backgroundTag":"invalid-object-reference","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}