{"record":{"id":"3a3d00462c950cfe","repo":"phacility/phabricator","slug":"failed-to-load-build-plan-s","errorCode":null,"errorMessage":"Failed to load build plan (\"%s\").","messagePattern":"Failed to load build plan \\(\"(.+?)\"\\)\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/harbormaster/storage/HarbormasterBuildable.php","lineNumber":106,"sourceCode":"\n    $buildable = self::createOrLoadExisting(\n      $viewer,\n      $phid,\n      $container_phid);\n\n    $plan_phids = mpull($requests, 'getBuildPlanPHID');\n    $plans = id(new HarbormasterBuildPlanQuery())\n      ->setViewer($viewer)\n      ->withPHIDs($plan_phids)\n      ->execute();\n    $plans = mpull($plans, null, 'getPHID');\n\n    foreach ($requests as $request) {\n      $plan_phid = $request->getBuildPlanPHID();\n      $plan = idx($plans, $plan_phid);\n\n      if (!$plan) {\n        throw new Exception(\n          pht(\n            'Failed to load build plan (\"%s\").',\n            $plan_phid));\n      }\n\n      if ($plan->isDisabled()) {\n        // TODO: This should be communicated more clearly -- maybe we should\n        // create the build but set the status to \"disabled\" or \"derelict\".\n        continue;\n      }\n\n      $parameters = $request->getBuildParameters();\n      $buildable->applyPlan($plan, $parameters, $request->getInitiatorPHID());\n    }\n  }\n\n  public function applyPlan(\n    HarbormasterBuildPlan $plan,","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/harbormaster/storage/HarbormasterBuildable.php#L88-L124","documentation":"HarbormasterBuildable::applyBuildPlans() receives build requests, each naming a build plan PHID, loads all plans in one query, and throws if any request's plan fails to load. Since the viewer is omnipotent, a miss means the plan row no longer exists — a HarbormasterBuildRequest is referencing a deleted build plan. Note that disabled plans are handled separately (skipped), so this is strictly about missing plans.","triggerScenarios":"A build request was created for a plan, and the plan was deleted before the request was processed (e.g. revision created, Herald applied a plan, plan deleted, daemon then runs applyBuildPlans). The exception surfaces in the worker task that starts builds for the buildable.","commonSituations":"Deleting build plans that are still selected by Herald rules or referenced by queued build requests; plan deleted via CLI/scripts without cleaning up requests; stale harbormaster_buildrequest rows after imports.","solutions":["Identify the dangling request: search harbormaster_buildrequest for the failing plan PHID and delete the orphaned rows (the buildable can then be re-triggered).","Update or delete the Herald rule / automation that still selects the deleted plan so new requests stop referencing it.","If the plan was deleted in error, restore it from a backup so pending requests can be processed.","After cleanup, re-run the daemon task or re-trigger the build (e.g. 'Request Build' / add a comment) to confirm builds start."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before processing build requests, drop or fix requests whose plan is gone:\n$plan_phids = mpull($requests, 'getBuildPlanPHID');\n$plans = id(new HarbormasterBuildPlanQuery())\n  ->setViewer(PhabricatorUser::getOmnipotentUser())\n  ->withPHIDs($plan_phids)\n  ->execute();\nforeach ($requests as $request) {\n  if (empty($plans[$request->getBuildPlanPHID()])) {\n    // orphaned request - delete it instead of letting applyBuildPlans throw\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["When deleting a build plan, also update Herald rules and clean pending build requests that reference it.","Audit Herald 'Add build plan' actions before removing plans.","Back up harbormaster_buildplan tables before bulk deletions."],"tags":["harbormaster","build-plan","phabricator"],"backgroundTag":"dangling-foreign-key-reference","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}