{"record":{"id":"c3f2aac27c96c355","repo":"phacility/phabricator","slug":"only-patches-in-the-s-namespace-may-contain-s","errorCode":null,"errorMessage":"Only patches in the '%s' namespace may contain '%s' keys.","messagePattern":"Only patches in the '(.+?)' namespace may contain '(.+?)' keys\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/infrastructure/storage/patch/PhabricatorSQLPatchList.php","lineNumber":140,"sourceCode":"        $full_key = \"{$namespace}:{$key}\";\n\n        if (isset($specs[$full_key])) {\n          throw new Exception(\n            pht(\n              \"%s '%s' has a patch '%s' which duplicates an \".\n              \"existing patch key.\",\n              __CLASS__,\n              get_class($patch_list),\n              $key));\n        }\n\n        $patch['key']     = $key;\n        $patch['fullKey'] = $full_key;\n        $patch['dead']    = (bool)idx($patch, 'dead', false);\n\n        if (isset($patch['legacy'])) {\n          if ($namespace != 'phabricator') {\n            throw new Exception(\n              pht(\n                \"Only patches in the '%s' namespace may contain '%s' keys.\",\n                'phabricator',\n                'legacy'));\n          }\n        } else {\n          $patch['legacy'] = false;\n        }\n\n        if (!array_key_exists('phase', $patch)) {\n          $patch['phase'] = $default_phase;\n        }\n\n        $patch_phase = $patch['phase'];\n\n        if (!isset($phases[$patch_phase])) {\n          throw new Exception(\n            pht(","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/infrastructure/storage/patch/PhabricatorSQLPatchList.php#L122-L158","documentation":"The 'legacy' key marks patches that predate the modern patch system and is meaningful only for Phabricator's own first-party storage. Third-party applications and libraries (any namespace other than 'phabricator') cannot declare legacy patches, so the loader rejects the key outright for them.","triggerScenarios":"A patch list whose getNamespace() returns something other than 'phabricator' returns a patch containing a 'legacy' key. This usually happens when copying an early patch from phabricator's own list into an application's list.","commonSituations":"Bootstrapping a new application by copying the head of Phabricator's core patch list (which starts with legacy patches); porting old pre-modern-patch-system definitions into a fork's extension.","solutions":["Delete the 'legacy' key from the patch in your application's list — it is meaningless outside the 'phabricator' namespace.","If you genuinely need first-party legacy semantics, the code must live in the phabricator namespace, which only the upstream project uses.","Re-run 'bin/storage status' to confirm the list loads."],"exampleFix":"// before (namespace: 'myapp')\n'0000.initial.sql' => array(\n  'type' => 'sql',\n  'name' => $this->getPatchPath('0000.initial.sql'),\n  'legacy' => true,\n),\n\n// after\n'0000.initial.sql' => array(\n  'type' => 'sql',\n  'name' => $this->getPatchPath('0000.initial.sql'),\n);","handlingStrategy":"validation","validationCode":"// Only the phabricator namespace may mark patches legacy:\n$list = new MyApplicationPatchList();\nif ($list->getNamespace() !== 'phabricator') {\n  foreach ($list->getPatches() as $patch) {\n    if (array_key_exists('legacy', $patch)) {\n      throw new Exception('Only the phabricator namespace may use the legacy key');\n    }\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Do not copy the head of Phabricator's core patch list (legacy-era entries) into application lists.","Treat 'legacy' as a frozen upstream-only flag; new patches never need it."],"tags":["phabricator","database-migration","legacy-migration","php"],"backgroundTag":"database-migration-validation","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}