{"record":{"id":"f8449edafc34b30d","repo":"phacility/phabricator","slug":"storage-patch-s-executes-in-phase-s-but-dep","errorCode":null,"errorMessage":"Storage patch \"%s\" executes in phase \"%s\", but depends on patch \"%s\" which is in a different phase (\"%s\"). Patches may not have dependencies across phases.","messagePattern":"Storage patch \"(.+?)\" executes in phase \"(.+?)\", but depends on patch \"(.+?)\" which is in a different phase \\(\"(.+?)\"\\)\\. Patches may not have dependencies across phases\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/infrastructure/storage/patch/PhabricatorSQLPatchList.php","lineNumber":235,"sourceCode":"      }\n    }\n\n    foreach ($specs as $key => $patch) {\n      foreach ($patch['after'] as $after) {\n        if (empty($specs[$after])) {\n          throw new Exception(\n            pht(\n              \"Patch '%s' references nonexistent dependency, '%s'. \".\n              \"Patches may only depend on patches which actually exist.\",\n              $key,\n              $after));\n        }\n\n        $patch_phase = $patch['phase'];\n        $after_phase = $specs[$after]['phase'];\n\n        if ($patch_phase !== $after_phase) {\n          throw new Exception(\n            pht(\n              'Storage patch \"%s\" executes in phase \"%s\", but depends on '.\n              'patch \"%s\" which is in a different phase (\"%s\"). Patches '.\n              'may not have dependencies across phases.',\n              $key,\n              $patch_phase,\n              $after,\n              $after_phase));\n        }\n      }\n    }\n\n    $patches = array();\n    foreach ($specs as $full_key => $spec) {\n      $patches[$full_key] = new PhabricatorStoragePatch($spec);\n    }\n\n    // TODO: Detect cycles?","sourceCodeStart":217,"sourceCodeEnd":253,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/infrastructure/storage/patch/PhabricatorSQLPatchList.php#L217-L253","documentation":"Storage patches execute in phases ('default' and 'worker') precisely so that a set of patches can complete before daemons restart during an upgrade. A dependency that crosses phases would make the phase split meaningless (the worker-phase patch might run before its default-phase dependency finishes), so the loader forbids it.","triggerScenarios":"A patch declares 'phase' => 'worker' (or a PHP patch header '// @phase worker') while its 'after' array names a patch in the 'default' phase — or vice versa. The phase comparison happens on the fully assembled global patch map.","commonSituations":"Moving a patch into the worker phase without moving the patches it builds on; adding a new dependency to an existing phased patch without checking that dependency's phase; forks cherry-picking phased patches onto a different base.","solutions":["Put the dependent patch in the same phase as its dependency (change its 'phase' key or '@phase' header).","Or remove the cross-phase dependency if the patches are actually independent.","If a whole chain must run early, move the first patch of the chain and all its dependents to the same phase.","Re-run 'bin/storage status' to confirm the constraint passes."],"exampleFix":"// before\n'20180102.jobs.sql' => array(\n  'type' => 'sql',\n  'name' => $this->getPatchPath('20180102.jobs.sql'),\n  'phase' => 'worker',\n  'after' => array('20180101.tables.sql'),   // default-phase patch\n),\n\n// after\n'20180102.jobs.sql' => array(\n  'type' => 'sql',\n  'name' => $this->getPatchPath('20180102.jobs.sql'),\n  'after' => array('20180101.tables.sql'),\n);","handlingStrategy":"validation","validationCode":"// Dependencies must not cross phases:\n$specs = PhabricatorSQLPatchList::buildAllPatches(); // itself enforces the rule\nforeach ($specs as $key => $patch) {\n  foreach ($patch['after'] as $after) {\n    if ($patch['phase'] !== $specs[$after]['phase']) {\n      throw new Exception(\"{$key} depends on {$after} across phases\");\n    }\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["When phasing a patch, phase its whole dependency chain or move the chain's head.","Keep a one-line comment on phased patches naming the phase so future dependencies are added consistently."],"tags":["phabricator","database-migration","phases","dependencies"],"backgroundTag":"database-migration-validation","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}