{"record":{"id":"e6b939351e55bf82","repo":"phacility/phabricator","slug":"s-s-has-a-patch-with-a-numeric-key-s-patc","errorCode":null,"errorMessage":"%s '%s' has a patch with a numeric key, '%s'. Patches must use string keys.","messagePattern":"(.+?) '(.+?)' has a patch with a numeric key, '(.+?)'\\. Patches must use string keys\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/infrastructure/storage/patch/PhabricatorSQLPatchList.php","lineNumber":102,"sourceCode":"          'phase' => true,\n        );\n\n        foreach ($patch as $pkey => $pval) {\n          if (empty($valid[$pkey])) {\n            throw new Exception(\n              pht(\n                \"%s '%s' has a patch, '%s', with an unknown property, '%s'.\".\n                \"Patches must have only valid keys: %s.\",\n                __CLASS__,\n                get_class($patch_list),\n                $key,\n                $pkey,\n                implode(', ', array_keys($valid))));\n          }\n        }\n\n        if (is_numeric($key)) {\n          throw new Exception(\n            pht(\n              \"%s '%s' has a patch with a numeric key, '%s'. \".\n              \"Patches must use string keys.\",\n              __CLASS__,\n              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","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/infrastructure/storage/patch/PhabricatorSQLPatchList.php#L84-L120","documentation":"Every patch in a PhabricatorSQLPatchList must be keyed by a descriptive string (conventionally 'YYYYMMDD.short.name.sql'). String keys become the patch's permanent identity ('namespace:key') used for ordering, dependency tracking, and remembering which patches are already applied. Numeric keys mean the entry has no usable identity, so loading the list fails.","triggerScenarios":"getPatches() returns an entry with an integer key — most often because the array key was omitted entirely ('array(...)' instead of \"'20180101.foo.sql' => array(...)\"), because the key is pure digits with no letters (e.g. '0000' or '20180101', which PHP treats as an integer), or because the list was combined with array_merge() which renumbers integer keys.","commonSituations":"Writing the first patch of a new application and using a bare date as the key; merging patch arrays with array_merge() (use '+' instead so string keys are preserved); refactoring a hand-written list into buildPatchesFromDirectory() output and losing keys.","solutions":["Give the offending patch a full conventional string key: 'YYYYMMDD.descriptive.name.sql'.","Make sure the key contains non-digit characters (a dot alone is enough) so PHP keeps it a string.","Replace any array_merge() on patch arrays with the '+' operator to avoid integer-key renumbering.","Re-run 'bin/storage status' to verify the list parses."],"exampleFix":"// before\nreturn array(\n  array(                        // no key -> numeric key 0\n    'type' => 'sql',\n    'name' => $this->getPatchPath('20180101.widget.sql'),\n  ),\n);\n\n// after\nreturn array(\n  '20180101.widget.sql' => array(\n    'type' => 'sql',\n    'name' => $this->getPatchPath('20180101.widget.sql'),\n  ),\n);","handlingStrategy":"validation","validationCode":"// Assert every key in your patch map is a non-numeric string:\nforeach ((new MyApplicationPatchList())->getPatches() as $key => $spec) {\n  if (is_numeric($key) || !is_string($key)) {\n    throw new Exception(\"Patch key must be a descriptive string: {$key}\");\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always key patches as 'YYYYMMDD.descriptive.name.sql' — the dot guarantees a non-integer string key.","Combine patch arrays with '+' (or foreach), never array_merge(), which renumbers integer keys.","Run 'bin/storage status' after editing any patch list."],"tags":["phabricator","database-migration","php","array-keys"],"backgroundTag":"database-migration-validation","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}