{"record":{"id":"f69641e6c5b91130","repo":"phacility/phabricator","slug":"s-s-has-a-patch-s-which-duplicates-an-exist","errorCode":null,"errorMessage":"%s '%s' has a patch '%s' which duplicates an existing patch key.","messagePattern":"(.+?) '(.+?)' has a patch '(.+?)' which duplicates an existing patch key\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/infrastructure/storage/patch/PhabricatorSQLPatchList.php","lineNumber":125,"sourceCode":"              get_class($patch_list),\n              $key));\n        }\n\n        if (strpos($key, ':') !== false) {\n          throw new Exception(\n            pht(\n              \"%s '%s' has a patch with a colon in the key name, '%s'. \".\n              \"Patch keys may not contain colons.\",\n              __CLASS__,\n              get_class($patch_list),\n              $key));\n        }\n\n        $namespace = $patch_list->getNamespace();\n        $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',","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/infrastructure/storage/patch/PhabricatorSQLPatchList.php#L107-L143","documentation":"Full patch keys ('namespace:key') must be globally unique across every installed patch list. When two patches resolve to the same full key, Phabricator cannot decide which one defines the schema state, so buildAllPatches() aborts. Note the duplicate is detected by full key, so two lists sharing one namespace, or one list repeating a key, both trip this.","triggerScenarios":"The same patch key appears twice in one getPatches() list (classic copy-paste: duplicating the previous entry and forgetting to change its key), or two PhabricatorSQLPatchList subclasses declare the same getNamespace() with overlapping keys.","commonSituations":"Copy-pasting the most recent patch entry to start a new one and forgetting to rename the key; merging two branches that both added a patch with the same date-prefixed name; accidentally registering two patch list classes with the same namespace.","solutions":["Search the named patch list class for the reported key; if it appears twice, rename the newer entry.","If you intended to copy an existing patch, give the new entry its own unique date-prefixed key.","If two classes share a namespace, fix getNamespace() so each application/library has a distinct one.","Re-run 'bin/storage status' to confirm uniqueness."],"exampleFix":"// before\nreturn array(\n  '20180102.gadget.sql' => array(\n    'type' => 'sql',\n    'name' => $this->getPatchPath('20180102.gadget.sql'),\n  ),\n  '20180102.gadget.sql' => array(            // duplicate key\n    'type' => 'sql',\n    'name' => $this->getPatchPath('20180103.gadget.index.sql'),\n  ),\n);\n\n// after\nreturn array(\n  '20180102.gadget.sql' => array(\n    'type' => 'sql',\n    'name' => $this->getPatchPath('20180102.gadget.sql'),\n  ),\n  '20180103.gadget.index.sql' => array(\n    'type' => 'sql',\n    'name' => $this->getPatchPath('20180103.gadget.index.sql'),\n  ),\n);","handlingStrategy":"validation","validationCode":"// Detect duplicate full keys across every installed patch list before storage runs:\nPhabricatorSQLPatchList::buildAllPatches(); // throws on duplicates\n// Or, for a single list:\n$keys = array_keys((new MyApplicationPatchList())->getPatches());\nif (count($keys) !== count(array_unique($keys))) {\n  throw new Exception('Duplicate patch keys in list');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["After duplicating a patch entry to start a new one, rename the key in the same edit — review the diff for repeated keys.","Give each application/library a unique getNamespace() so full keys cannot collide across lists."],"tags":["phabricator","database-migration","duplicate-key","php"],"backgroundTag":"database-migration-validation","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}